jasonacox / pypowerwall

Python API for Tesla Powerwall and Solar Power Data
MIT License
123 stars 21 forks source link

Pass through Powerwall Web interface and customize for iframe displays #14

Closed danisla closed 2 years ago

danisla commented 2 years ago

Hello,

This PR adds support to the proxy feature of pypowerwall to proxy access to the Powerwall web interface and customize it's appearance.

This lets you run the proxy on a local network and create iframe widgets for displays like Dakboard.

image

jasonacox commented 2 years ago

Thank you, @danisla! This is a great addition! A few things in my testing:

Great job on this! Thanks for the PR.

image
jasonacox commented 2 years ago

Update: Another issue I found is that the pass through would not work if you used a hostname or IP address. Using localhost worked on Chrome and Brave browsers. I was able to get it to work for all hostnames and on Safari. I had to remove the send_header() attributes "path=/;SameSite=None;Secure;" From what I can tell, that is only proper if you use HTTPS but since the proxy is HTTP, they were causing the browser to ignore the auth cookies. I added the ability to make the proxy serve HTTPS via an environmental setting. I need to run more tests and build an iframe demo to ensure all cases and all browsers work (http and https). I suspect there are still issues with iframes.

Can you see if the changes still work with your Dakboard?

danisla commented 2 years ago

@jasonacox thanks for the feedback! I run the pypowerwall proxy in http mode behind an https proxy and I missed the localhost and IP cases, thanks for catching those.

For ideal iframe support, the proxy would need to run in https mode with a valid cert and have the SameSite=None; and Secure; cookie suffixes.

I tested this with PW_HTTPS=yes on my Dakboard and it wouldn't load with the self-signed certificate, there isn't really a way to bypass the cert exception on the iframe without modifying the root certs.

Maybe if the pypowerwall proxy had an option to set the https mode cookiesuffix, while running in http mode like this, that would fix it for my case where my ssl termination is done upstream. I'm open to other solutions too.

Another thing I noticed is that the cookie should be set with the path=/; prefix in all cases, otherwise you get multiple cookies set for the /api paths too:

if(https_mode == "yes"):
    cookiesuffix = "path=/;SameSite=None;Secure;"
    httptype = "HTTPS"
else:
    cookiesuffix = "path=/;"
    httptype = "HTTP"

Also FYI, the web app has an indexedDB requirement which means the web app doesn't work in some browsers or in incognito where indexedDB is blocked. (I was running my dakboard on an RPI with Chromium in incogntio and the web app iframe wouldn't load, but disabling incognito fixed it)

jasonacox commented 2 years ago

Thanks @danisla! I think we could have a PW_HTTPS=http mode that adds the SameSite suffix without adding another env:

if https_mode == "yes":
    # run https mode with self-signed cert
    cookiesuffix = "path=/;SameSite=None;Secure;"
    httptype = "HTTPS"
elif https_mode == "http":
    # run http mode but simulate https for proxy behind https proxy
    cookiesuffix = "path=/;SameSite=None;Secure;"
    httptype = "HTTP"
else:
    # run in http mode
    cookiesuffix = "path=/;"
    httptype = "HTTP"

Is there a way to detect if indexedDB is blocked? If so, we could have it send a message to the user to disable incognito.

jasonacox commented 2 years ago

Hi @danisla - I made some updates:

I'm now soak testing the latest build to ensure no memory leaks or other issues.

Again, THANK YOU for all your help and the great contribution!

danisla commented 2 years ago

Awesome, glad to be of help.

Thank you for creating and maintaining this project!

jasonacox commented 2 years ago

One update in case you pull, I changed the js injection to use clear.js which uses 'transparent' background to make it easier to place on multiple projects. I made this a configurable option via PW_STYLE="clear" environmental variable that pulls in the corresponding js file. Options are: clear (default), black, white, grafana gray, and dakboard black (your original). It is not an elegant solution but does work.

FYI - I also released an updated Grafana dashboard thanks to your help: https://github.com/jasonacox/Powerwall-Dashboard/discussions/26

Thanks again, Dan!