Git Product home page Git Product logo

pypowerwall's People

Contributors

dailow avatar danisla avatar dcgibbons avatar derickjohnson avatar dkerr64 avatar emptywee avatar igcherkaev avatar jasonacox avatar jordanbelford avatar mcbirse avatar nhasan avatar niabassey avatar rcasta74 avatar venturanc avatar wcw-cmu-edu avatar zi0r avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pypowerwall's Issues

Extra connection created?

I have my pypowerwall.env connection/cache settings like this:

PW_CACHE_EXPIRE=60
PW_POOL_MAXSIZE=1

I am seeing logs that look like this showing a lot of discarded connections. Why is it creating extra connections when there "should only be one"? Could this be a problem?

04/24/2024 09:54:00 AM [urllib3.connectionpool] [WARNING] Connection pool is full, discarding connection: 192.168.7.87. Connection pool size: 1
04/24/2024 09:57:00 AM [urllib3.connectionpool] [WARNING] Connection pool is full, discarding connection: 192.168.7.87. Connection pool size: 1
04/24/2024 09:59:00 AM [urllib3.connectionpool] [WARNING] Connection pool is full, discarding connection: 192.168.7.87. Connection pool size: 1
04/24/2024 10:01:00 AM [urllib3.connectionpool] [WARNING] Connection pool is full, discarding connection: 192.168.7.87. Connection pool size: 1
04/24/2024 10:01:39 AM [proxy] [INFO] pyPowerwall Proxy Stopped
 CANCEL 
04/24/2024 10:01:56 AM [proxy] [INFO] pyPowerwall [0.8.3] Proxy Server [t54] - HTTP Port 8675
04/24/2024 10:01:56 AM [proxy] [INFO] pyPowerwall Proxy Started
04/24/2024 10:01:56 AM [proxy] [INFO] pyPowerwall Proxy Server - Local Mode
04/24/2024 10:01:56 AM [proxy] [INFO] Connected to Energy Gateway 192.168.7.87 (Harrison)
04/24/2024 10:02:00 AM [urllib3.connectionpool] [WARNING] Connection pool is full, discarding connection: 192.168.7.87. Connection pool size: 1
04/24/2024 10:04:00 AM [urllib3.connectionpool] [WARNING] Connection pool is full, discarding connection: 192.168.7.87. Connection pool size: 1
04/24/2024 10:06:00 AM [urllib3.connectionpool] [WARNING] Connection pool is full, discarding connection: 192.168.7.87. Connection pool size: 1
04/24/2024 10:11:00 AM [urllib3.connectionpool] [WARNING] Connection pool is full, discarding connection: 192.168.7.87. Connection pool size: 1
04/24/2024 10:17:00 AM [urllib3.connectionpool] [WARNING] Connection pool is full, discarding connection: 192.168.7.87. Connection pool size: 1

INFO: Alerts displayed when one Powerwall is defective

The alerts below are all showing for me with one defective Powerwall in the group. Gateway disabled this battery due to communication failures - possibly due to a failed firmware upgrade. Tesla said the battery needs to be replaced under warranty service.

"GridCodesWrite",
"GridCodesWrite",
"GridCodesWrite",
"GridCodesWriteError",
"FWUpdateFailed",
"BatteryDisabled",
"PodCommissionTime",
"SystemConnectedToGrid",
"PINV_a067_overvoltageNeutralChassis",
"PINV_a067_overvoltageNeutralChassis",
"PINV_a067_overvoltageNeutralChassis",
"THC_w042_POD_MIA",
"SYNC_a001_SW_App_Boot"

Proxy cache-control not set correctly

Setting Cache-Control in server.py here is not done correctly. This line of code

self.send_header("Set-Cookie", "Cache-Control: no-cache")

is incorrect as cache control is not a cookie, it is it's own header field. The correct code is:

self.send_header("Cache-Control", "no-cache, no-store")

Note that I added no-store. I did this because when analyzing what the Testa Powerwall returns when I connect the browser directly to the Powerwall, I see both no-cache and no-store. I believe this is to support older browsers.

Okay, so, by default pyPowerwall should set no-cache, no-store by fixing this bug.

But not caching has severe performance implications when reloading a page with embedded power flow animation graphics. We should provide an option that lets a user indicate that they want to permit a browser to cache resources. I propose a setting.
PW_BROWSER_CACHE=<seconds>
and if this is set to anything non-zero then

browser_cache = int(os.getenv("PW_BROWSER_CACHE", "0"))
if browser_cache > 0:
    self.send_header("Cache-Control", "max-age={}".format(browser_cache))
else:
    self.send_header("Cache-Control", "no-cache, no-store")

This dramatically improves page load (after the first load) until whatever number of seconds expires and then the browser will fetch the resources again (on page reload). A user can always force the reload by holding down the shift key.

image

Notice the resources that are now retrieved from memory.

Now, we could further refine this. Rather than setting the header before the data is retrieved from Powerwall, wait until after so that the content-type is known. If content-type is text/css, application/javascript or image/png then use max-age else do not permit caching. Specifically application/json should never be permitted to cache. This is what appears to be happening by default, but I don't know if that is coincidence or not... It's not really coincidence (as coded right now) because that data is coming from <ipaddr>:8675/api/xxxx that are in the ALLOWLIST so it is not going through the proxy code.

So, it might be safer to move the header code down a few lines where we already have...
ftype = r.headers['content-type']
and then add

browser_cache = int(os.getenv("PW_BROWSER_CACHE", "0"))
# Allow browser caching, if user permits, only for CSS, JavaScript and PNG images...
if browser_cache > 0 and (ftype == 'text/css' or ftype == 'application/javascript' or ftype == 'image/png'):
    self.send_header("Cache-Control", "max-age={}".format(browser_cache))
else:
    self.send_header("Cache-Control", "no-cache, no-store")

And finally, I would move the first line up to where all the other environment variables are retrieved.

David

Critical Bug - 404 HTTP Status Code Handling

There is a bug identified in the current pypowerwall release on how 404 HTTP status codes are handled.

Firmware version 23.44.0 has eliminated /api/devices/vitals resulting in a 404 response from the Powerwall Gateway (TEG) when this is requested. There is a bug in the pypowerwall code that will treat this 404 like an authentication failure which will result in attempts to log in over and over, eventually hitting the rate limit. This is especially impactful for those using the proxy for things like Powerwall-Dashboard as the rate limit will prohibit other data gathering.

Related issue: #57

A fix is underway...

Implement HTTP persistent connections for API requests

I've noticed API requests to the Powerwall gateway are not using HTTP persistent connections (aka keep-alive or connection re-use), which results in every request opening a new connection to the gateway and closing again.

There can be a lot of requests being sent to the gateway, even more so if the Power Flow is being viewed via the proxy as with the default Grafana dashboard of the Powerwall-Dashboard (~7 additional requests every few seconds).

I assume the constant open/close of HTTP connections might cause more load on the Powerwall, not to mention the continual requirement for new TCP sockets and such. My Powerwall has been a bit flaky sometimes where it stopped responding for a while, which could be attributed to overloading it perhaps?

So, to potentially reduce the load and make pypowerwall more efficient with API requests to the gateway, I was thinking it would be better to utilise HTTP connection re-use and pooling.

This appears to be simple enough by using a Session object of the Requests module. I will submit a PR with my code changes for this.

Using the Session object results in HTTP connections to the gateway remaining established via keep-alive and being re-used with each API request. There could be multiple connections to the gateway (pooling), but this will be limited by the max pool size (10 by default, which seemed fine in my testing).

I ended up doing a fair amount of before/after testing of this change, as I wanted to quantify and validate that it was in fact beneficial?

I also did resilience testing with Powerwall-Dashboard and the pypowerwall proxy, to ensure there were no adverse affects. i.e. Testing what happens if an established HTTP connection was purposefully broken, invalidating the auth cookie to see if a re-login would occur, disrupting the network connection to the gateway for a while, etc. All my tests passed, with the connection to the gateway re-establishing okay without any user intervention or having to restart the pypowerwall proxy. πŸ‘

Anyway, I thought I would include findings from my before/after testing for anyone interested...

@jasonacox - let me know what you think? This appears to be a very worthwhile change I believe. I think I just missed the v0.5.1 release as I was typing this out when released! v0.6.0 maybe? 😊

And sorry for such a long post! But hopefully the below testing might also be informative to others (as it was for me).


Firstly, I wanted to see what happens regarding HTTP connections direct to the gateway using a standard web browser. As my Powerwall is in a DMZ on my network, I used my firewall to view the TCP connections.

When browsing direct to the gateway (i.e. not via pypowerwall proxy), only 1 persistent HTTP TCP connection is used. With the browsers dev tools, the network activity showed requests being sent every second or so over this connection.
image

By comparison, when viewing the TCP connections to the gateway coming from the Powerwall-Dashboard and pypowerwall, I was seeing constant open/established/close of connections, using different ports.
image

After changing pypowerwall to use persistent HTTP connections however, it then behaves like a standard web browser by using keep-alive to keep connections established and re-use them for API requests, with multiple connections up to the pool max. Nice!
image

I also used the example test script to check connection use and measure any performance improvements. For the test purposes, I set pwcacheexpire=0 in the script to disable the pypowerwall caching.

Before the changes, debug output shows each API request creates a new HTTP connection.
image

After modifying pypowerwall to use persistent HTTP connections, only 1 connection is established and used for each API request.
image

Regarding the performance differences for the above, I measured the elapsed time of sending the set of requests over several iterations, with a 5 second delay between each set.

Before any changes, the time taken for each set of requests to complete was ~1 second.
image

When re-using a single HTTP connection however, the response time was significantly reduced, taking around only 0.25 seconds.
image

So, there definitely appears to be a benefit here, potentially reducing the load on the Powerwall gateway, while also improving response times!

Powerwall not reachable ever since January 26th

Ever since January 26th my pypowerwall container keeps restarting every minute. In the log it shows that it's unable to connect to the powerwall. However the powerwall is running just fine and accessible through the Tesla app. What can I do to figure out where the issue is ?

Screen Shot 2024-01-30 at 21 39 16 PM

Powerwall Firmware Upgrade 22.26.1-foxtrot 4d562eaf - Bugs in Proxy

The latest Powerwall Firmware upgrade to 22.26.1-foxtrot 4d562eaf resulted in a few bugs with the pyPowerwall proxy.

  • The /version API does not respond. This is due to an exception caused by the unexpected "-foxtrot" suffix.
  • The iFrame rendered animation via proxy may cause flashing and results in a "compliance" text link in the graphic that wasn't there before.

image

@danisla Do you know if the "compliance" text in the animation graphic could be easily fixed?

New PW firmware seems to break vitals - 23.44.0

I like to begin by saying thank you for everyone's time, energy, and efforts toward this project; its been phenomenal to learn and use!

At 11:38pm last night I noticed that the pypowerwall was having authentication issues, I had to use the forget password function to reset the gateway password. Once I restarted everything I noticed that pypowerwall was no longer getting vitals and that the firmware version seems to be new.

output:

Device Version:
 23.44.0 eb113390

Device Vitals:
 None

generated by:

import pypowerwall

password='xxx'
email='xxx'
host = "xxx"
timezone = "America/Los_Angeles" 

pw = pypowerwall.Powerwall(host,password,email,timezone)

print("Device Version:\n %s\n" % pw.version())
print("Device Vitals:\n %s\n" % pw.vitals(True))

Memory leak in pypowerwall proxy

From @youzer-name jasonacox/Powerwall-Dashboard#25 (comment)

I use Grafana and InfluxDB to monitor my Pi4's vital stats. Recently I noticed that my memory used was steadily climbing. When I checked the Task Manager in the Pi4 GUI I found that Python3 was using a lot of memory in the "VM-Size" column. After rebooting the Pi the total memory use dropped down a lot.

I've been watching the memory usage since my last reboot about 6 days ago. While pypowerwall isn't the only thing using more memory, restarting my pypowerwall container immediately dropped the total memory usage by about 11%. The memory use by Python3 dropped from over 400MB to < 20MB. Based on the numbers I saw before the reboot, I expect that if I had let it go longer, the Python3 memory utilization would have just continued to climb.

Is this normal or could there be a memory leak in pypowerwall or Python3?

This image shows the last 7 days. Towards the left you can see the before/after reboot. At the very right edge you can see the restart of the pypowerwall docker container.

image

Originally posted by @youzer-name in jasonacox/Powerwall-Dashboard#25

Cannot set reserve lower than 5%

Is there a reason I can't set a reserve lower than 5? I get no response from the API when I set a value lower than 5.

Ideally I want to set the reserve to 0 as 0 set by cloud is actually 5% SoC if you look at the local API's battery level. At the moment setting the value to 5 leaves me at a local 10% SoC.

Is there a description of the fields?

I'm trying create some dashboards based on the data collected by pypowerwall and my greatest problem is a understanding of the fields and their values

i.E:

  • what is site and load
  • what are the 3 power fields and their difference?
instant_power: 62
instant_reactive_power: -253
instant_apparent_power: 260.48608408128064
  • what are the energy_imported and energy_exported fields?

Thanks for clarification

Dakky

Add grid_status function

Provide a call to /api/system_status/grid_status

from https://github.com/vloschiavo/powerwall2 the return values would be:

{"grid_status":"SystemGridConnected","grid_services_active":false}
{"grid_status":"SystemGridConnected"} = grid is up
{"grid_status":"SystemIslandedActive"} = grid is down
{"grid_status":"SystemTransitionToGrid"} = grid is restored but not yet in sync.

if verbose=True then return the full json which would include grid_services_active

Modification to poll() defaults

Two things related to poll()

  1. When creating the Powerwall object, it would be good to pass in a cache_expiration parameter that can adjust the cache expiration
  2. It would be good to be able to override the cache with a Fetch=True parameter to poll()

If I make a pull request and make these changes, would you be interested in accepting them?

Tool script set_mode.py error

Raised by user:

The script set_mode.py has been working but in the past few days it has failed. Here is the me what I see.

Traceback (most recent call last):
File "C:\Users\dgpet\Documents\Projects\Python\Powerwall\set-mode.py", line 299, in
mode = data["operation"]
KeyError: 'operation'

I have dumped the β€˜data’ though I don’t have a copy of successful one to compare too.. Anything I can do to help?

Confirmed that the data payload no longer contains 'operation' key.

PyPowerwall stopped connecting

Pypowerwall proxy stops working when the pypowerwall.env file has PW_CONTROL_SECRET set. If the value is empty things work on. This happens for me on both the latest container and jasonacox/pypowerwall:0.8.4t54-beta2

Env

[email protected]
PW_PASSWORD=password
PW_HOST=192.168.7.87
PW_TIMEZONE=America/Chicago
PW_STYLE=grafana-dark
TZ=America/Chicago
PW_DEBUG=no
PW_CACHE_EXPIRE=30
PW_POOL_MAXSIZE=1
PW_CONTROL_SECRET=password.here

Logs

2024-04-18 16:14:08 NameError: name 'pw_control' is not defined
2024-04-18 16:14:09 04/18/2024 04:14:09 PM [proxy] [INFO] pyPowerwall [0.8.4] Proxy Server [t54] - HTTP Port 8675
2024-04-18 16:14:09 04/18/2024 04:14:09 PM [proxy] [INFO] pyPowerwall Proxy Started
2024-04-18 16:14:09 04/18/2024 04:14:09 PM [proxy] [INFO] pyPowerwall Proxy Server - Local Mode
2024-04-18 16:14:09 04/18/2024 04:14:09 PM [proxy] [INFO] Connected to Energy Gateway 192.168.7.87 (Harrison)
2024-04-18 16:14:09 04/18/2024 04:14:09 PM [proxy] [INFO] Control Commands Activating - WARNING: Use with caution!
2024-04-18 16:14:09 04/18/2024 04:14:09 PM [pypowerwall.cloud.pypowerwall_cloud] [WARNING] Missing auth file .auth/.pypowerwall.auth - run setup
2024-04-18 16:14:09 04/18/2024 04:14:09 PM [proxy] [ERROR] Control Mode Failed: Unable to connect to cloud - Run Setup
2024-04-18 16:14:09 Traceback (most recent call last):
2024-04-18 16:14:09   File "/app/server.py", line 205, in <module>
2024-04-18 16:14:09     if pw_control:
2024-04-18 16:14:09 NameError: name 'pw_control' is not defined

Scan

Host: 192.168.7.87 ... OPEN - Found Powerwall 1232100-00-H--GF2231140002H0
                     [Firmware 23.44.0 eb113390]

Redefinition of ThreadingHTTPServer in server.py and server-r.py

Hi @jasonacox,

I'm not quite sure what is happening here, but the code in the server modules is doing something odd. Using server.py as the example:

  • Line 19 imports ThreadingHTTPServer
    from http.server import BaseHTTPRequestHandler, HTTPServer, ThreadingHTTPServer
    
  • Lines 110-112 appear to redefine ThreadingHTTPServer
    class ThreadingHTTPServer(ThreadingMixIn, HTTPServer):
        daemon_threads = True
        pass
    
  • Line 347 instantiates the result.

From a quick object inspection, line 347 creates server with base classes of HTTPServer and ThreadingMixIn (from line 110) - which is not helpful, because these are the base classes we would expect from the redefinition and also the base classes for ThreadingHTTPServer ...

Is this what you intended or should lines 110-112 be removed and line be modified to:

from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer

I'm guessing the latter?

(This is an aside triggered by the ToU stuff I'm putting together - which unfortunately could be made thread unsafe very easily!).

Slow charge speed from grid?

Back when you could set reserve on the local PowerWall gateway API it would always charge from the grid at the full 5kw.

When that broke I switched to using ToU in the Tesla app, and it always pulled 5kw from the grid when charging.

Now I've switched to pypowerwall and am setting the reserve, it only seems to be charging at ~1850W from the grid.

This may be coincidental of course and I have something else going on.

Any thoughts?

set-reserve ERROR gives Missing access token parameter. Auth token expired?

Hi,

python3 set-reserve.py --read
fails with this error:

ERROR: Failed to retrieve PRODUCT_LIST - (missing_token) Missing access token parameter.

I guess the problem is that the auth token has expired as I have the following in the set-reserve.auth file:
... "expires_in": 28800, "token_type": "Bearer", "expires_at": 1700028409.1826518}}}
which can be converted as expires_in 8 hours and expires_at Wednesday, November 15, 2023 6:06:49 AM GMT .

Is there a way to automatically refresh the token without having to login again?
Can it be embedded in set-reserve.py and the other tools?

Thanks

PVAC_a030_fan_faulted

I believe this alert to be when an inverter fan is failing / failed.
I’m getting this on my system and the corresponding graphs for inverter are showing β€œclipping” (or drops in power)

alerts
IMG_0151

graphs
IMG_0149
IMG_0148

New Tesla Pros software update does not work with pypowerwall

Tesla's firmware 23.28.2 no longer supports the old way of getting metrics as far as I can see. Going to my Powerwall's IP address I get "Switch to Tesla Pros for a better commissioning experience. The current experience is no longer supported"

The pypowerwall app says it connects but there are not any metrics:
10/13/2023 05:13:32 PM [proxy] [INFO] pyPowerwall [0.6.2] Proxy Server [t27] - HTTP Port 8675
10/13/2023 05:13:32 PM [proxy] [INFO] pyPowerwall Proxy Started

Will pypowerwall support the newer Tesla Pros application?

Please tag new release for 0.6.1

I'm maintaining the FreeBSD port for pypowerwall and have noticed that the new Powerwall-Dashboards require the /alerts/pw call to exist.

Would you be able to tag a new release so I can update the port and get this functionality out to the world?

Thanks!

detailed battery function

You can get detailed battery information from the 'system_status' api call. In particular, you get

            "Type": "",
            "PackagePartNumber": "3012170-10-B",
            "PackageSerialNumber": "TGxxxxx",
            "disabled_reasons": [],
            "pinv_state": "PINV_GridFollowing",
            "pinv_grid_state": "Grid_Compliant",
            "nominal_energy_remaining": 13803,
            "nominal_full_pack_energy": 13803,
            "p_out": 0,
            "q_out": 0,
            "v_out": 248.60000000000002,
            "f_out": 60.007999999999996,
            "i_out": -0.4,
            "energy_charged": 12780,
            "energy_discharged": 740,
            "off_grid": false,
            "vf_mode": false,
            "wobble_detected": false,
            "charge_power_clamped": false,
            "backup_ready": true,
            "OpSeqState": "Active",
            "version": "b0ec24329c08e4"

What do you think of having a detailed_battery() call that returns this information plus adds a temperature value from the vitals() data?

The parameters would follow the the verbose=True to return the JSON. Otherwise, return a dict structure per battery with the two nominal energy readings and the temperature.

Set minimum backup reserve level for battery

Firstly, another outstanding bit of coding.

The documentation says: This python module can be used to monitor and control Tesla Energy Powerwalls.

I imagine this has been discussed many times but there is a train of thought that forcing the backup level to 100% forces the Powerwall to charge no matter what option is chosen and thus override the Tesla "algorithm". I know people who wait until the off peak time (10 PM or perhaps 11 PM for daylight savings) to change their battery backup reserve to 100% and then get up before the peak time (usually 7 AM) to ensure they are not charging during peak hours.

So can this code do that? I can't (probably not looking hard enough) find anything to say set backup reserve to 100%. Then something could poll the battery to ensure it reaches 100% before peak time, set the battery reserve back to say 15%. Importing from the grid seems to be set to 3.5 kWh so a 13.5 kWh battery needs around 4 hours to charge from 10%.

I generally just leave my battery alone but it would be interesting to see how this could work. A couple of wet cloudy days really screws with charging and more often than not, the "algorithm" doesn't pick the weather and my battery will not charge.

Regards

Stephen

pyPowerwall [0.8.3] Proxy Server [t53] testing

These aren't unique to 0.8.2, but thought you'd like to see them regardless with all the new error handling.

2024-04-12 22:01:05 04/12/2024 10:01:05 PM [proxy] [ERROR] Socket broken sending API response to client [doGET]: [Errno 32] Broken pipe
2024-04-12 22:01:05 04/12/2024 10:01:05 PM [proxy] [ERROR] Socket broken sending API response to client [doGET]: [Errno 32] Broken pipe
2024-04-12 22:01:06 04/12/2024 10:01:06 PM [proxy] [ERROR] Socket broken sending API response to client [doGET]: [Errno 32] Broken pipe
2024-04-12 22:01:08 04/12/2024 10:01:08 PM [proxy] [ERROR] Socket broken sending API response to client [doGET]: [Errno 32] Broken pipe
2024-04-12 22:01:08 04/12/2024 10:01:08 PM [proxy] [ERROR] Socket broken sending API response to client [doGET]: [Errno 32] Broken pipe
2024-04-12 22:31:10 04/12/2024 10:31:10 PM [proxy] [ERROR] Socket broken sending API response to client [doGET]: [Errno 32] Broken pipe
2024-04-12 22:31:10 04/12/2024 10:31:10 PM [proxy] [ERROR] Socket broken sending API response to client [doGET]: [Errno 32] Broken pipe
2024-04-12 22:31:11 ----------------------------------------
2024-04-12 22:31:11 Exception occurred during processing of request from ('172.18.0.6', 42768)
2024-04-12 22:31:11 Traceback (most recent call last):
2024-04-12 22:31:11   File "/usr/local/lib/python3.10/socketserver.py", line 683, in process_request_thread
2024-04-12 22:31:11     self.finish_request(request, client_address)
2024-04-12 22:31:11   File "/usr/local/lib/python3.10/socketserver.py", line 360, in finish_request
2024-04-12 22:31:11     self.RequestHandlerClass(request, client_address, self)
2024-04-12 22:31:11   File "/usr/local/lib/python3.10/socketserver.py", line 747, in __init__
2024-04-12 22:31:11     self.handle()
2024-04-12 22:31:11   File "/usr/local/lib/python3.10/http/server.py", line 433, in handle
2024-04-12 22:31:11     self.handle_one_request()
2024-04-12 22:31:11   File "/usr/local/lib/python3.10/http/server.py", line 421, in handle_one_request
2024-04-12 22:31:11     method()
2024-04-12 22:31:11   File "/app/server.py", line 321, in do_GET
2024-04-12 22:31:11     fcv["grid_status"] = pw.grid_status(type="numeric")
2024-04-12 22:31:11   File "/app/pypowerwall/__init__.py", line 616, in grid_status
2024-04-12 22:31:11     grid_status = payload['grid_status']
2024-04-12 22:31:11 TypeError: 'NoneType' object is not subscriptable
2024-04-12 22:31:11 ----------------------------------------

Change the path .auth & .site files are saved to

I'm running pypowerwall in an Unraid docker, but am having to re-perform the setup process each time I make a change to the docker and the image is refreshed.

It would be great to be able to define a custom path for .pypowerwall.auth and other volatile config related files so I can store them outside of the root file structure. Then in Unraid I can redirect a container path to a host path.

How would I achieve this?

Alert Code feedback

Adding some feedback on alert codes, and my understanding of what some of them mean:

BackfeedLimited - I believe this controls backfeed before PTO, under the "Permission to Operate" option under the settings menu. Prior to PTO the backfeed rate is limited, as the system needs to produce over the load, but by the minimum possible. The system seems to regulate this by switching MCI's open/closed, to minimize the overage that must be backfed, as the power has to go somewhere, and at this point the batteries are 100%. This seems to toggle that setting per inverter. I was told by Tesla that one of my two powerwalls were still stuck in this mode, post PTO, because of some software glitch that doesn't always toggle all devices to on, when selecting Yes to operate from the app.

RealPowerAvailableLimited - Seems related to the above

POD_w031_SW_Brick_OV
POD_w044_SW_Brick_UV_Warning
POD_w045_SW_Brick_OV_Warning
I believe all the Brick warnings are related to preventing the condition where the powerwall doesn't have the minimum amount of power it needs to turn back on. When this happens, a third party charger is needed to get the powerwall back to it's minimum operating battery requirement to turn back on, or it's "bricked". Solar cannot return it to this state, because it needs power to make power.

python3 set-reserve.py --read error

Greetings,

Version v0.7.7 Tesla Firmware 23.44.0

I just installed the latest version and I have the right set-reserve.auth and set-reserve.conf. However, when I tried to run the following command, it produces this:

python3 set-reserve.py --read
Traceback (most recent call last):
File "/home/pi/pypowerwall/tools/set-reserve.py", line 313, in
data = get_level()
File "/home/pi/pypowerwall/tools/set-reserve.py", line 264, in get_level
data = battery.get_site_info()
AttributeError: 'Battery' object has no attribute 'get_site_info'

I can get info out of the battery by using the example.py so it seems the local account is good. This used to work with an older version but I haven't tried recently.

Thanks

Stephen

Issues with POST

Things have stopped working for me since you implemented POST.

I can set the reserve correctly using POST using curl from your example, but when I set the method in my node-red function to POST it says my token is bad.

"{"unauthorized": "Control Command Token Invalid"}"

I'm not sure what I'm doing wrong. It should be as simple as changing msg.method in my custom function:

if (powerwall_reserve!=charge_level && overnight_charge===true) {
    msg.method = "POST"
    msg.url = "http://192.168.78.40:8675/control/reserve?token=MY_TOKEN&value=" + charge_level
return msg;

The only thing I can see different is your example sets the value before the token. Should this matter?

Any ideas?

pypowerwall container for arm64 and arm/v7

Open issue for Greg Rhan - See jasonacox/Powerwall-Dashboard#1

Thanks for putting together your [Powerwall Monitor] - looks great!
I'm trying to get it set up and it looks like your pypowerwall container may not be built for arm (I'm on a M1 Mac and Raspberry Pi v3b+). Any chance you could update the docker image to support linux/arm64 & linux/arm/v7 in addition to amd64? Thanks in advance.

From my Pi
$ docker logs pypowerwall
standard_init_linux.go:228: exec user process caused: exec format error
standard_init_linux.go:228: exec user process caused: exec format error
standard_init_linux.go:228: exec user process caused: exec format error

From my M1 Mac

image

Augmenting battery_blocks

battery_blocks() merges battery specific information from /api/system_status and /api/device/vitals

Currently, it is only pulling data from the TETHC block but more information is available in the TPOD and TINV blocks.

Pulling data from those blocks is a little harder since we'd have to match against the componentParentDin to find the battery serial number.

There should also be some thought on which design path to take when pulling in the info from the other blocks as, at first glance, there may be the same data already exposed via system_status. As such, we'd want to consider whether battery_blocks() should provide a merged view of all data or present the TPOD/TINV data in a separate block. I'd probably lean towards providing more data fidelity and show the data provenance, over ease of access.

Powerflow background is transparent, not black.

When I access x.x.x.x:8675/ for the powerflow animation, the background of the page is transparent, and I can't see the current battery percentage without highlighting the text on the page.

Did I miss a configuration step?

image

If I look at the page source and change the CSS background to black, it looks great, but then I think it autorefreshes and goes back to background=transparent.

Proxy connect to hostname vs IP

Why does the PW_HOST setting in the env file have to be an IP address? I tried setting it to the hostname of the Gateway, but the container complains that it can't connect. Why would I want to use the hostname? If my Access Point reboots for an update, the gateway disconnects and falls back to the ethernet connection...which has a DIFFERENT IP address. Which means that the dashboard isn't getting any data. By specifying a hostname instead of an IP address, the proxy will ALWAYS be able to connect to the gateway, regardless of if it's connected via WiFi or ethernet.

Ran upgrade.sh but it does not pull all new files

Ran the upgrade.sh script to update to latest version, expected tessolarcharge.py script to be available under 'tools' folder but could not find this script after the update.

These are what can be found under tools after running the update:

-rw-r--r-- 1 pi pi 3532 Oct 4 20:36 DOCKER.md
drwxr-xr-x 2 pi pi 4096 May 8 2023 ecowitt-weather-history
drwxr-xr-x 2 pi pi 4096 Mar 28 2023 fixmonthtags
drwxr-xr-x 5 pi pi 4096 May 8 2023 influxdb2
drwxr-xr-x 2 pi pi 4096 Mar 28 2023 mysql
drwxr-xr-x 2 pi pi 4096 Mar 28 2023 pvoutput
drwxr-xr-x 2 pi pi 4096 Jul 3 17:11 pwstatus
-rw-r--r-- 1 pi pi 4540 Dec 4 23:12 README.md
drwxr-xr-x 2 pi pi 4096 Dec 4 23:12 solar-only
drwxr-xr-x 2 pi pi 4096 Dec 4 23:12 tesla-history
drwxr-xr-x 2 pi pi 4096 Oct 16 22:09 usage-service
drwxr-xr-x 2 pi pi 4096 Jul 3 17:11 weather-history

Changing Battery Configuration State Via GET

I noticed that you added a control surface for the battery reserve. I am very excited about this for my needs. Thank you all for working on this. πŸ’―

I was curious why you made the request a GET and not a POST? Maybe this has already been debated. My history with creating web APIs points to avoiding using GETs in front of anything that changes the state of the world.

Feel free to close this if I am being too pedantic.

Thanks again.

Powerwall Solar Vitals and String Data for External Inverters

This is a cross-reference link to a discussion at vloschiavo/powerwall2#51 on the Tesla Powerwall Gateway /api/devices/vitals endpoint. This issue is to troubleshoot and help provide help getting real time string data to trend and identify system issues.

By "string" I mean each string of solar panels that are connected together and terminated at the Powerwall solar inverter. The Powerwall+ allows for 4 strings each, identified as A, B, C and D. If you have multiple inverters, the pyPowerwall pw.strings() function will append a number to the letter to accommodate multiple inverters (A, B, C, D, A1, B1, C1, D1, A2, ...).

Vitals Background

  • The /api/devices/vitals endpoint responds with a protobuf binary payload. Thanks to the great work by @brianhealey, we have a tesla.proto file that can be used to create python interfaces to the data. pyPowerwall now uses this to decode the vitals payload through two simple functions, vitals() and strings():
# Install pyPowerwall package
pip install pypowerwall
import pypowerwall

# Credentials for your Powerwall - Customer Login Data
password='password'
email='[email protected]'
host = "localhost"                # Change to the IP of your Powerwall
timezone = "America/Los_Angeles"  # Change to your local timezone/tz

# Connect to Powerwall
pw = pypowerwall.Powerwall(host,password,email,timezone)

# Display Vitals (returns details as dictionary or JSON)
vitals = pw.vitals(jsonformat=False)
print(vitals)

# Display String Data 
strings = pw.strings(jsonformat=False)
print(strings)

String Data

I wanted to be able to capture string data to see if my system was performing correctly. If you want to see it in human readable format, just specify jsonformat as True like this:

strings = pw.strings(jsonformat=True)
print(strings)

Output:

{
    "A": {
        "Connected": true,
        "Current": 0.48,
        "Power": 115.0,
        "State": "PV_Active",
        "Voltage": 251.8
    },
    "B": {
        "Connected": false,
        "Current": 0.0,
        "Power": 0.0,
        "State": "PV_Active",
        "Voltage": -2.3999999999999995
    },
    "C": {
        "Connected": true,
        "Current": 1.82,
        "Power": 526.0,
        "State": "PV_Active",
        "Voltage": 293.6
    },
    "D": {
        "Connected": true,
        "Current": 1.81,
        "Power": 521.0,
        "State": "PV_Active_Parallel",
        "Voltage": 294.0
    }
}

I push that into a tiny installation of Splunk (see TinySplunk) and get a graph like this:

image

Here is an example script I used to pull the string data and stuff it into Splunk:

# pyPowerwall - Powerwall Solar String data to Splunk

from splunk_http_event_collector import http_event_collector
import logging
import sys
import pypowerwall

# Credentials for your Powerwall - Customer Login Data
password='password'
email='[email protected]'
host = "localhost"                # Change to the IP of your Powerwall
timezone = "America/Los_Angeles"  # Change to your local timezone/tz

# Connect to Powerwall
pw = pypowerwall.Powerwall(host,password,email,timezone)

# Grab strings data from Powerwall
strings = pw.strings(jsonformat=False)

# init logging config, this would be job of your main code using this class.
logging.basicConfig(format='%(asctime)s %(name)s %(levelname)s %(message)s', datefmt='%Y-%m-%d %H:%M:%S %z')

# Create event collector object, default SSL and HTTP Event Collector Port
http_event_collector_key = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
http_event_collector_host = "10.1.1.101"

# Setup Splunk HEC Connector
splunk = http_event_collector(http_event_collector_key, http_event_collector_host)
splunk.log.setLevel(logging.ERROR)
    
# perform a HEC reachable check
hec_reachable = splunk.check_connectivity()
if not hec_reachable:
    sys.exit(1)

# break apart JSON into event items
event = {}
try:
    for k, v in strings.items():
        # key and value are payload event items
        event.update({k:v})
    
    # Build payload with metadata information
    payload = {}
    payload.update({"index":"main"})
    payload.update({"sourcetype":"solar-strings"})
    payload.update({"source":"http-stream"})
    payload.update({"host":"pypowerwall"})
    payload.update({"event":event})
    splunk.sendEvent(payload)
    
    splunk.flushBatch()

except:
    print("ERROR: Unable to send")

I created a dashboard graphs with Splunk queries like this:

* sourcetype="solar-strings" | timechart span=5m avg(A.Power) as "A" avg(B.Power) as "B" avg(C.Power) as "C" avg(D.Power) as "D"

Neruio Solar Meter Monitoring

I also have occasional trouble with the Neruio solar meter that Tesla installed in my Powerwall+ so I also have scripts to watch that. It shows up in the vitals payload as a device that I monitor and capture to create alerts (e.g. if it doesn't show up in the vitals payload that means it has lost connection with the gateway and shut down solar production):

"NEURIO--VAHxxxxxxxxxx": {
        "NEURIO_CT0_InstRealPower": 1333.5606370817025,
        "NEURIO_CT0_Location": "solar",
        "Parent": "STSTSM--xxxxxxx-00-E--TGxxxxxxxxxxxx",
        "firmwareVersion": "1.6.1-Tesla",
        "lastCommunicationTime": "1638720520",
        "manufacturer": "NEURIO",
        "partNumber": "",
        "serialNumber": "VAHxxxxxxxxxx"
    }

I have a script that pulls this out of the vitals payload and stuffs it into Splunk as well. Below is an example showing a dropout where the Neurio loses connection and reconnects:

image

Splunk queries:

sourcetype="solar-meter" 
|  eval connected=state*(-1000)
| timechart span=5m  avg(power) as Power avg(connected) as Connected

sourcetype="solar-meter" 
| eval tsmax=if(ts == 0, _time, ts)
| eval delay=_time-tsmax 
| timechart span=5m   avg(delay) as Delay

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.