jasonacox / Powerwall-Dashboard

Grafana Monitoring Dashboard for Tesla Solar and Powerwall Systems
MIT License
293 stars 61 forks source link

Negative Solar Values #302

Closed aesculus closed 1 year ago

aesculus commented 1 year ago

I have a bit of an unusual situation with my Powerwall setup that Tesla had to get involved in to remedy. The problem is that I have three solar systems, two of which are traditionally connected with the inverter breakers inside the PW gateway. The third solar system inverter breaker is installed an another subpanel that also has loads on it.

What would happen is that during the day when solar was being produced any load from that panel would be subtracted from the total solar production. Somehow Tesla was able to put 2 CTs on the GW (one for solar and one for loads) on the same circuit. Through some unknown magic in Tesla's back end, this all works correctly. The Tesla app shows the correct values when loads are turned on and off in that panel for both Home and Solar.

In the Powerwall Dashboard it is reading the actual CT values and the solar is getting reduced by the loads that are on the panel. Trying to figure out the weird math that Tesla is doing is beyond expectation but where it really is an issue is during non solar production. During non solar production these loads appear as negative solar values.

So at night the base load is 35 W which shows as -35W solar, and if I turn on lights in that panel then the negative solar is proportional (ie -300W).

So is there a way to at least set any negative solar values to 0 in the Powerwall Dashboard before placing them into the DB?

In this image you can see the negative solar starting at 20:00 when I had lights on a for a few hours.

image

mcbirse commented 1 year ago

So is there a way to at least set any negative solar values to 0 in the Powerwall Dashboard before placing them into the DB?

Hey @aesculus - I posted a discussion here in #112 that would allow you do this.

You could use a telegraf starlark script to filter the solar metrics before they are written to InfluxDB. I do this myself due to very small negative solar values when there is no production (i.e. night time) and would rather these be recorded as zeros.

Interesting issue however... I am wondering if there would be a way to reconfigure your CT connections for it to see correct values? I guess a knowledgeable electrician would be required and they seem hard to find sometimes.

aesculus commented 1 year ago

I'll look at the telegraf script idea. Can you post what you did here? I would be satisfied with throwing out the negative values to start with. Fixing the reduced solar output based on the loads is a whole nother kettle of fish.

Actually Tesla came up with the solution using two sets of CTs and some magic in the back end. Before that it was not acceptable. Now from the Tesla app perspective its perfect. So they are doing some magic with the two CT feeds which I really connect figure out. Without this hack I was going to have to have some sort of remote CT read just for the breaker with the inverter on it and that was going to be problematic since its 400 feet away with a bunch buildings blocking signals etc.

mcbirse commented 1 year ago

I'll look at the telegraf script idea. Can you post what you did here? I would be satisfied with throwing out the negative values to start with.

Sure - below is an example cut-down version of the script that would do just what you need (set negative solar values to zero).

  1. Edit your telegraf.local file
  2. Add a section for [[processors.starlark]] and then add your source script

The example telegraf.local script below does the following:

# Set negative solar values to zero
[[processors.starlark]]
  namepass = ["http"]
  source = '''
def apply(metric):
  solrpwr = metric.fields.get("solar_instant_power")

  if solrpwr != None:
    if solrpwr < 0:
      metric.fields["solar_instant_power"] = 0.0

  return metric
'''

After saving telegraf.local with your changes, restart the container to start using the filter:

# Restart telegraf
docker restart telegraf

If you have log output in your filter or to check for errors, you can view this as follows:

# View telegraf logs
docker logs -f telegraf

Check the full discussion thread #112 for more info however and other examples.

Fixing the reduced solar output based on the loads is a whole nother kettle of fish.

If you can work out what magic Tesla did with the values, perhaps you can replicate those calculations so the correct data is being logged to InfluxDB.

aesculus commented 1 year ago

OK. I put the script into the telegraph.local and restarted telegraph. When the load exceeds the solar the Solar Generation on the Current State is now 0. Note though that the Power Flow animation still shows that negative 200 watts (which is the load I put on that circuit). Not sure where that is being fed from.

image

Another interesting tidbit that may be helpful in solving the bigger picture: Note the difference between the battery discharge (980W) and the Home using (758W) which is about 220W. This is not what is shown on the Tesla app. In that instance both are showing the same amount. And the grid is 0 (Idle). Remember on that circuit that has the remote solar (the one that can go negative), that value is also used in the home load. So it appears that Tesla may be playing a game where any load on that circuit gets worked into the home load and they compare the PW discharge to what the home is reporting.

I need to do some investigation and find out what is actually measured and what is calculated. I know that solar is measure. I also know that home loads are measured. I am not sure about grid (don't think so because I have no CTs on the meter side that I am aware of. I think the PW discharge are measured.

So once I know what is actually measured I can probably come up with some algorithms to play games with sources and sinks that don't line up with various other readings during certain operations. I suspect now that is what Tesla is doing but it's outside the scope of their API I guess since it's being done in the back end and not the PW local.

jasonacox commented 1 year ago

The power flow animation is pulling the raw live numbers from the Powerwall GW (not InfluxDB) so it won't represent the changes you did to telegraf, unfortunately. That gives more indication that Tesla is doing this on the backend.

Are you able to see all the CT values in the vitals payload (e.g. http://localhost:8675/vitals)? If you can figure out the equation they are using with the values from vitals, you could replicate that in telegraf for the translated values. Or alternatively, create a specialized pypowerwall (server.py) that does the translation for you (no telegraf translation needed). The advantage of that is that it would also show up correctly in the power flow animation.

aesculus commented 1 year ago

I'll looking into the python route. Still scratching my head on the math. Once I have the pieces laid out it might become more clear.

aesculus commented 1 year ago

Looking over the CT output I cannot recreate what is happening at all to make the Power Flow simulator.

What py file is currently driving that?

BTW the CSV output does seem to match the values.

jasonacox commented 1 year ago

Hi @aesculus - the proxy is the server.py file. It uses the pypowerwall python library to "proxy" the API calls. The

These links might help troubleshoot by using the pypowerwall container:

I suspect the API that would need to be adjusted would be: /api/meters/aggregates - right now server.py just passes this payload directly to the user (telegraf or the animation). I don't know which of these you would need to intercept and adjust but this section in server.py would be where you would add that:

https://github.com/jasonacox/pypowerwall/blob/fa35955b4b45a9de7809265b6811d61c2bd9dae5/proxy/server.py#L132-L134

Of course, all of that means that you have to figure out how Tesla is computing the real values on the backend.

Example payload from /api/meters/aggregates

{
    "site": {
        "last_communication_time": "2023-06-13T19:28:59.922501695-07:00",
        "instant_power": 444,
        "instant_reactive_power": 421,
        "instant_apparent_power": 611.863546879531,
        "frequency": 0,
        "energy_exported": 2843735.345945686,
        "energy_imported": 4872980.200026697,
        "instant_average_voltage": 209.86393609908302,
        "instant_average_current": 8.592500000000001,
        "i_a_current": 0,
        "i_b_current": 0,
        "i_c_current": 0,
        "last_phase_voltage_communication_time": "0001-01-01T00:00:00Z",
        "last_phase_power_communication_time": "0001-01-01T00:00:00Z",
        "last_phase_energy_communication_time": "0001-01-01T00:00:00Z",
        "timeout": 1500000000,
        "num_meters_aggregated": 1,
        "instant_total_current": 8.592500000000001
    },
    "battery": {
        "last_communication_time": "2023-06-13T19:28:59.916289015-07:00",
        "instant_power": 1120,
        "instant_reactive_power": -40,
        "instant_apparent_power": 1120.714058089752,
        "frequency": 59.997,
        "energy_exported": 9102210,
        "energy_imported": 10278620,
        "instant_average_voltage": 242.5,
        "instant_average_current": -32.300000000000004,
        "i_a_current": 0,
        "i_b_current": 0,
        "i_c_current": 0,
        "last_phase_voltage_communication_time": "0001-01-01T00:00:00Z",
        "last_phase_power_communication_time": "0001-01-01T00:00:00Z",
        "last_phase_energy_communication_time": "0001-01-01T00:00:00Z",
        "timeout": 1500000000,
        "num_meters_aggregated": 2,
        "instant_total_current": -32.300000000000004
    },
    "load": {
        "last_communication_time": "2023-06-13T19:28:59.916289015-07:00",
        "instant_power": 1515,
        "instant_reactive_power": 373.5,
        "instant_apparent_power": 1560.3612562480523,
        "frequency": 0,
        "energy_exported": 0,
        "energy_imported": 20759944.854081012,
        "instant_average_voltage": 209.86393609908302,
        "instant_average_current": 7.218963048919102,
        "i_a_current": 0,
        "i_b_current": 0,
        "i_c_current": 0,
        "last_phase_voltage_communication_time": "0001-01-01T00:00:00Z",
        "last_phase_power_communication_time": "0001-01-01T00:00:00Z",
        "last_phase_energy_communication_time": "0001-01-01T00:00:00Z",
        "timeout": 1500000000,
        "instant_total_current": 7.218963048919102
    },
    "solar": {
        "last_communication_time": "2023-06-13T19:28:59.930135427-07:00",
        "instant_power": 120,
        "instant_reactive_power": -10,
        "instant_apparent_power": 120.41594578792295,
        "frequency": 59.995999999999995,
        "energy_exported": 19907110,
        "energy_imported": 0,
        "instant_average_voltage": 241.9,
        "instant_average_current": 0.49586776859504134,
        "i_a_current": 0,
        "i_b_current": 0,
        "i_c_current": 0,
        "last_phase_voltage_communication_time": "0001-01-01T00:00:00Z",
        "last_phase_power_communication_time": "0001-01-01T00:00:00Z",
        "last_phase_energy_communication_time": "0001-01-01T00:00:00Z",
        "timeout": 1000000000,
        "num_meters_aggregated": 1,
        "instant_total_current": 0.49586776859504134
    }
}
aesculus commented 1 year ago

OK. Something to dive into after this weekend.

The Power Flow animation does seem to use the CSV call to display its data. I might have to do a bit more experimenting with toggling on/off loads to see where the values show up.

aesculus commented 1 year ago

I think I figured out the algorithm and it's actually pretty simple, and not totally accurate during solar production times, but good enough.

To recapitulate: One of my solar inverters is in a distribution panel that also has loads on it (mostly lighting). It has CTs both on the load side and on the solar side.

Here is what appears to be happening:

If the system is producing solar and the load is less than the total solar production then the load side looks negative and it is ignored. Note that any load reduces the value of the solar so it will be in error.

If the system is producing solar and the load is bigger than the solar then the solar goes negative and is ignored, and the load (home side) gets the remainder added to it. Again this is not totally accurate because the amount of solar being produced is the error. See pictures attached.

If there is no solar then the load side is accurate and is added to the home load. The solar will be negative and be ignored.

These pictures represent a seneario where there is 200 Watts of solar being generated with 300 Watts of load on the same panel.

image

This is the current Powerwall-Dashboard without the correction algorithms. Note the negative solar and the amount of home load.

image

This is the Tesla app version with Tesla's tweaking of the data on the back end. Note the solar is 0 and the home load is 100 Watts (300W load - 200W solar) higher than the PW Dashboard raw data view.

BuongiornoTexas commented 1 year ago

Hi @aesculus - From that description, it sounds like both CTs are configured as solar - one should be configured as solar and one as load (and is really something your installer should be sorting - solar should not be showing significant negative values. I'd be making it their problem to sort out).

The gateway is set up so each CT can be toggled according to what it is reading and the internals do the balancing for you.

(The more cynical view is that they may only have put in one CT and all you are seeing is the net output from that one CT - like @jasonacox says, I'd be digging deeper into the API to see what measurements you actually having coming into the gateway).

aesculus commented 1 year ago

@BuongiornoTexas - My setup is a bit weird. I have a solar system installed in a remote building. Both Tesla and I thought it was easiest just to monitor the panel vs the individual circuits since that would require two sets of very expensive remote CTs to be 100% accurate for the rare case I have significant loads at the same time as I was producing solar. Right now the only significant loads (> 50 W) are at night when the sun is not shining and there is no solar, and even then it's about 300W.

So Tesla fixed this by having two sets of CTs on the same circuit basically. One is with the normal backup load CTs where the circuit is part of the bundle, and the other being a separate set only on that breaker that is tied into the solar set.

In the back end Tesla is doing some math to throw away the solar that is negative (the nighttime lighting on the solar breaker). And with the Tesla app, everything looks correct.

What I need to figure out is how they are dealing with the negative generation of solar that is tied into the site load. Since the API does not deal with CTs directly, but with the A/B phases of the combined site and solar CTs. I have a bit more investigation to do here. I need to figure out how they are not reducing my site load during solar production on that circuit.

BuongiornoTexas commented 1 year ago

Hi @aesculus - Fair enough - I'm struggling to picture this in my head. If you could provide a sketch of what is going on with your CTs, load and solar circuits, we might be able to provide more useful thoughts on your issue.

You can probably also get some useful info on how the CTs are configured by looking at these three pages.

http://pypowerwall.host:8675/api/meters/ http://pypowerwall.host:8675/api/meters/site http://pypowerwall.host:8675/api/meters/solar

From these you should be able to see which CTs are assigned to site and solar and which are inverted - which is a software switch that corrects for CTs installed backwards for the expected current flow (we had a solar line which was reporting negative exports when the sun was shining - flipping this switch was a lot easier than shutting the house down for the sparky to reverse the CT!). Also from my comments, you should be getting a picture that you can't rely on Tesla and their installers to get things right first time - it took 3 post install visits/changes to get our system fully sorted out.

(Edit out your serial numbers/short ids if you post any data here).

Be warned that the transition from raw meter data to aggregate goes through a bit of Tesla massaging, so it may be hard to reconcile numbers.

aesculus commented 1 year ago

@jasonacox I could use a bit of obvious information on where to place the server.py file in a Powerwall-Dashboard implementation.

I think I am ready to experiment with my modifications but don't see the server.py file in my current installation. There is one in the weather folder but I doubt that is the place to modify it? Also what would I need to do to ensure this gets used to feed the PWDB? Is there a setting somewhere or just its presence?

BuongiornoTexas commented 1 year ago

@aesculus - I think you may be looking for pypowerwall. https://github.com/jasonacox/pypowerwall. In particular, server.py in the proxy folder.

aesculus commented 1 year ago

That is true but I have no clue how to integrate it into the Dashboard. So looking for a cheat sheet.

jasonacox commented 1 year ago

For development, here is what i do... You can create a script to run it on the host and pass in the environmentals. First, you clone pypowerwall and move into the proxy directory:

git clone https://github.com/jasonacox/pypowerwall.git
cd pypowerwall/proxy

Edit server.py as needed... then start it up:

# Start up pypowerwall for testing
export PW_PASSWORD="password"
export PW_EMAIL="email"
export PW_HOST="x.x.x.x"
export PW_TIMEZONE="America/LosAngeles"
export PW_DEBUG="yes"
echo "Starting proxy at http://localhost:8675..."
python3 server.py

You should be able to see stats at: http://localhost:8675/stats values at http://localhost:8675/aggregates or the animation at http://localhost:8675/example.html

# Tests
curl -i http://localhost:8675/soe
curl -i http://localhost:8675/aggregates

Once it is working, you will need to create a container - see this doc: https://github.com/jasonacox/pypowerwall/tree/main/proxy#build-your-own

Key being:

# Build for local architecture  
docker build -t pypowerwall:latest .

# Run it as a test
docker run \
-d \
-p 8675:8675 \
--name pypowerwall \
--restart unless-stopped \
pypowerwall

You will then need to modify the docker compose file (powerwall.yml) to use the docker version you just built (removing jasonacox and version). This is the section:

https://github.com/jasonacox/Powerwall-Dashboard/blob/18ff67bcb433eeaa00731c2d417bbe267202e4a8/powerwall.yml#L22-L33

I'm sorry... it's a bit complicated. There is also a strong change that I missed something or had a typo above. I'm traveling this week and unable to test. Good luck! And have fun... that's the whole point, right? šŸ˜‰

aesculus commented 1 year ago

Just what I needed. I will on it and report back when successful, or fail misserably.

BuongiornoTexas commented 1 year ago

If you are doing your development on the same machine as your main dashboard docker setup, you'll also want to change the port for your test server. Otherwise you'll have two services sitting on 8675.

aesculus commented 1 year ago

Good point. I'll get it working as an alternative port first and then when all is OK, I will swap it.

aesculus commented 1 year ago

@jasonacox OK. A bit dense here. Tried installing it with just copying various files. Failed when it could not import pypowerwall when running scan or other script.

Dropped back to using PIP to install and when running scan after it was OK. Looked at the folder where pip installed it and did not find anything different that what I manually copied (ie nothing to import).

So what am I missing here?

I also probably need to better understand pip too. I called it from my self made pypowerwall folder but in reality it put it deep into the users folder structure under python3.

jasonacox commented 1 year ago

Quick background: PIP is the way Python manages packages (libraries). It stands for "Pip Installs Packages"(ha!) and uses the Python Package Index (PyPI). PyPI is a repository for software packages in the Python programming language. You use pip (command line) to install, upgrade, and manage Python packages from PyPI.

PyPowerwall is a python package (the source code of which is located in the pypowerwall folder inside the repo). You can run it by cloning the package (as mentioned above) but you will need to run your code (updated server) that use that package from the root folder of that repo. The import command will first look to see if you have the local files before looking at the pip libraries you have installed. I published pypowerwall on PyPI so most users will not need to clone the repo, they just need to run pip install pypowerwall.

For the Powerwall-Dashboard project, I have made it somewhat confusing by using a container named pypowerwall but this is NOT the same as the python package. It is actually a bit of code (server.py) that provides a proxy server to a Powerwall that happens to use the python pypowerwall library. I bunded this proxy up into a docker container and stored it on DockerHub as pypowerwall instead of pypowerwall-proxy or something more definitiave (sorry).

For the purposes of this work you are doing, you will need both. Install the package pip install pypowerwall and then git clone https://github.com/jasonacox/pypowerwall.git to download the example proxy server.py code so you can modify it.

# install python library
pip install pypowerwall

# install code that contains example server.py
git clone https://github.com/jasonacox/pypowerwall.git
cd pypowerwall/proxy

# Start up pypowerwall proxy server for testing
export PW_PASSWORD="password"
export PW_EMAIL="email"
export PW_HOST="x.x.x.x"
export PW_TIMEZONE="America/LosAngeles"
export PW_DEBUG="yes"
export PW_PORT="8999"
echo "Starting proxy at http://localhost:8999..."
python3 server.py
aesculus commented 1 year ago

OK. Way out of my league and the QNAP support of Python3 is terrible at best.

I have run into this issue trying to start the proxy server:

Traceback (most recent call last): File "/share/CACHEDEV1_DATA/pypowerwall/proxy/server.py", line 28, in <module> from transform import get_static, inject_js File "/share/CACHEDEV1_DATA/pypowerwall/proxy/transform.py", line 3, in <module> from bs4 import BeautifulSoup as Soup ModuleNotFoundError: No module named 'bs4'

jasonacox commented 1 year ago

Welcome to the fun of python programming! šŸ˜

You can install the bs4 module: pip install beautifulsoup4

FWIW, I find that ChatGPT can also help: https://chat.openai.com/share/53a0b68f-b8da-4b21-baef-e5f28b0b4270

aesculus commented 1 year ago

Welcome to the fun of python programming! šŸ˜

I only have so many slots for tech platforms. The dance card is already filled. And the problem is you cannot delete the old stuff like FORTRAN once you use it. :-)

You can install the bs4 module: pip install beautifulsoup4

FWIW, I find that ChatGPT can also help: https://chat.openai.com/share/53a0b68f-b8da-4b21-baef-e5f28b0b4270

OK. Installed. I am up and running on port 8999. Now for a few days of experimenting with different scenarios and then it will be off to create the new pypowerwall container. Stand by.

jasonacox commented 1 year ago

The dance card is already filled

šŸ¤£ Just keep dancing!

I am up and running on port 8999.

Great job!

aesculus commented 1 year ago

@jasonacox Lets say I want to alter the value of the instant_power in the solar meter aggregates in server.py.

What would I modify in lines 132-133 before posting the message back in 134?

"solar": { "last_communication_time": "2023-06-13T19:28:59.930135427-07:00", "instant_power": 120,

jasonacox commented 1 year ago

To modify the JSON data and add 1000 (as an example) to the "solar" "instant_power" value in a Python script, you can use the json module to parse the JSON string, update the value, and then convert it back to a JSON string. Here's an example:

        if self.path == '/aggregates' or self.path == '/api/meters/aggregates':
            # Meters - JSON
            jsonpayload = pw.poll('/api/meters/aggregates')
            # Parse JSON string
            data = json.loads(jsonpayload)
            # Update the "instant_power" value in "solar"
            data["solar"]["instant_power"] += 1000
            # Convert back to JSON string
            message = json.dumps(data)
aesculus commented 1 year ago

Thanks for the python lesson.

BuongiornoTexas commented 1 year ago

Thanks for the python lesson.

If you want to get into it, humble bundle routinely has very good introductory/mid level python book bundles for very low cost. I've collected 10-15 O'Reilly books over the years for almost nothing. They also have no starch press stuff, which has an excellent reputation as well.

aesculus commented 1 year ago

No. I was actually being sarcastic. While python is a great language, I am done learning new things. But thanks for the pointer anyway. I am sure someone following this thread in the future will gain from it.

aesculus commented 1 year ago

@jasonacox Done with coding and checked it out OK. Made the pypowerwall docker image OK.

I also see I have a pypowerwall and two jasoncox/pypowerwall (0.6.2t26 and latest with same date and time) images in docker.

I see how to change the powerwall.yml.

So can I just stop and remove the standard pypowerwall container and then after changing the powerwall.yml rerun the ./setup.sh for my pypowerwall image to become the one the container is based on?

I suspect I don't have to delete the jasoncox/pypowerwall images since they won't be installed after making the yml change?

jasonacox commented 1 year ago

You should only need to update the powerwall.yml to point to your local pypowerwall image you built:

    pypowerwall:
        image: pypowerwall
        container_name: pypowerwall
        hostname: pypowerwall
        restart: always
        user: "1000:1000"
        ports:
            - target: 8675
              published: 8675
              mode: host
        env_file:
            - pypowerwall.env

Then run:

./compose-dash.sh up -d
aesculus commented 1 year ago

Ugh. I am back to that issue again with the DNS=[] rather than null again. I did not change that part of the yml and the standalone command

docker run -d -p 8675:8675 --name pypowerwall --restart unless-stopped pypowerwall

did not result in null either. Now I have to try to figure out why that is! Anything you can think might have forced the DNS [] thing when building the docker image?

jasonacox commented 1 year ago

Did we ever figure out why it didn't originally work here? https://github.com/jasonacox/Powerwall-Dashboard/issues/288. I looked though that issue again can't find where it was fixed. Did it just work when you "started over"?

Perhaps a full restart of the stack? ./compose-dash.sh down and ./compose-dash.sh up -d

aesculus commented 1 year ago

The only thing I changed in the pypowerwall.yml was jasonacox/pypowerwall:0.6.2t26 > pypowerwall

And BTW after the full restart it has null rather than [] but still refuses to connect

I did an inspect on both the working and non working containers and the only thing that was different besides the obvious numbers and dates were:

"PYTHON_VERSION=3.10.12" where yours is "PYTHON_VERSION=3.10.11" "Image": "pypowerwall" where yours is "Image": "jasonacox/pypowerwall:0.6.2t26" "Gateway": "172.29.0.1" where yours is "Gateway": "172.29.4.1" "IPAddress": "172.29.0.2" where yours is "IPAddress": "172.29.4.2"

jasonacox commented 1 year ago

Did you stop the old one? Since they are using the same port, only one will be able to run. Also, check the logs. But, the network difference is interesting. It is like the docker networking isn't set up right. I would suggest removing the full stack including the docker networking and start over:

./compose-dash.sh down
./compose-dash.sh up -d
aesculus commented 1 year ago

I did the full compose with down first. I will try log tomorrow.

Seems odd that pypowerwall gets the low ip address.

Chris Couper

On Mon, Jun 26, 2023, 9:45 PM Jason Cox @.***> wrote:

Did you stop the old one? Since they are using the same port, only one will be able to run. Also, check the logs. But, the network difference is interesting. It is like the docker networking isn't set up right. I would suggest removing the full stack including the docker networking and start over:

./compose-dash.sh down ./compose-dash.sh up -d

ā€” Reply to this email directly, view it on GitHub https://github.com/jasonacox/Powerwall-Dashboard/issues/302#issuecomment-1608790542, or unsubscribe https://github.com/notifications/unsubscribe-auth/AACFFZAAJ7LEOCTXRAAITBDXNJQQLANCNFSM6AAAAAAZDYOZPI . You are receiving this because you were mentioned.Message ID: @.***>

aesculus commented 1 year ago

Attached is the log. Seems to be a name resolution issue. Note there were no errors when creating the image in docker but perhaps my environment is not perfect.

This is running the container as a separate app.

py_log.txt

This was my 'major' code change.

            # Meters - JSON
            # mod for negative loads on solar circuits
            jsonpayload = pw.poll('/api/meters/aggregates')
            # Parse JSON string
            data = json.loads(jsonpayload)
            # Update the "instant_power" value in "solar"
            if data["solar"]["instant_power"] < 0:
                data["solar"]["instant_power"] = 0
            # Convert back to JSON string
            message = json.dumps(data)
            # message = pw.poll('/api/meters/aggregates')
jasonacox commented 1 year ago

requests.exceptions.ConnectionError: HTTPSConnectionPool(host='hostname', port=443): Max retries exceeded with url: / (Caused by NameResolutionError("<urllib3.connection.HTTPSConnection object at 0x7f47e7990070>: Failed to resolve 'hostname' ([Errno -2] Name does not resolve)"))

This is curious. It is like the Environmental variables are not loading, specifically PW_HOST, which is causing the name lookup issue. The file pypowerwall.env should contain something like:

PW_EMAIL=email@example.com
PW_PASSWORD=password
PW_HOST=10.0.1.2
PW_TIMEZONE=America/Los_Angeles
PW_DEBUG=no

And that should be set via docker-compose in the yaml file:

        env_file:
            - pypowerwall.env

but it appears that it is not loading for some reason in you configuration. Can you check that the pypowerwall.env looks right and is the same folder where you run the ./compose-dash.sh up -d?

aesculus commented 1 year ago

Yeah. I literally run the standard version of containers from my powerwall.yml and then all I do is to change this:

pypowerwall: image: pypowerwall

So from the same folder and all other files are untouched.

I can flip flop from working to not working just by making that change from the standard pypowerwall image.

I can only think it's something in my docker build environment. BTW I tried it with a virgin server.py file and its the same host issue.

jasonacox commented 1 year ago

I tend to agree. It is very odd. However, I think I would try this:

# remove all pypowerwall images
docker stop pypowerwall
docker rm pypowerwall
docker images | grep pypowerwall | awk '{print $3}' | xargs docker rmi -f

# rebuild pypowerwall
cd pypowerwall/proxy
docker build -t pypowerwall:latest .
docker images
REPOSITORY                        TAG            IMAGE ID       CREATED         SIZE
pypowerwall                       latest         84534cd0f129   8 seconds ago   58.5MB

# rebuild stack
./compose-dash.sh up -d
docker logs pypowerwall -f

If that didn't work, I would try to run it separately:

docker run \
-d \
-p 9123:9123 \
-e PW_PORT='9123' \
-e PW_PASSWORD='password' \
-e PW_EMAIL='email@example.com' \
-e PW_HOST='x.x.x.x' \
-e PW_TIMEZONE='America/Los_Angeles' \
-e TZ='America/Los_Angeles' \
-e PW_CACHE_EXPIRE='5' \
-e PW_DEBUG='no' \
-e PW_HTTPS='no' \
--name pypowerwall2 \
--restart unless-stopped \
pypowerwall

# test
curl localhost:9123/version
{"version": "23.4.2-2 f8afd6b6", "vint": 230422}

# check port mappings
docker ps
CONTAINER ID   IMAGE                            COMMAND                  CREATED         STATUS         
70fe7cad9b35   pypowerwall                      "python3 server.py"      3 minutes ago   Up 3 minutes   
    PORTS                                                 NAMES
    8675/tcp, 0.0.0.0:9123->9123/tcp, :::9123->9123/tcp   pypowerwall2
aesculus commented 1 year ago

OK. That did it. Working now.

Now I have to fix my logic. I cannot just set the solar value to 0 but have to add whatever the value was to the load side, otherwise it no longer balances. I am assuming this is because the aggregate is after the math to figure out the load. The .3kW difference is the 300W negative solar value I wiped out and set to 0.

Is there a API call to adjust the solar before aggregate does its math, or should I just take from solar and give to load?

temp

This is without the solar math

image

jasonacox commented 1 year ago

You will need to do the math. The APIs just pull from what the Powerwall is reporting. We can't adjust its math.

Where does the 300W come from and can we get that data from any of the API calls? Or do you mean that any negative amount in Solar should be added to the load?

            # Meters - JSON
            # mod for negative loads on solar circuits
            jsonpayload = pw.poll('/api/meters/aggregates')
            # Parse JSON string
            data = json.loads(jsonpayload)
            # Update the "instant_power" value in "solar" and "load"
            if data["solar"]["instant_power"] < 0:
                data["load"]["instant_power"] += abs(data["solar"]["instant_power"])
                data["solar"]["instant_power"] = 0
            # Convert back to JSON string
            message = json.dumps(data)
            # message = pw.poll('/api/meters/aggregates')
aesculus commented 1 year ago

Where does the 300W come from and can we get that data from any of the API calls?

One of my sets of Solar CTs is on a panel with lighting loads, so if lights are on it goes negative. To be exact there is always a base load of 35 W on that circuit but that is a rounding error.

Or do you mean that any negative amount in Solar should be added to the load?

Yes, because it is a load. The code you wrote should do it.

aesculus commented 1 year ago

Success:

image

image

aesculus commented 1 year ago

BTW I think this statement fixed the problem but I even tried deleting the image before too and it did not make any difference.

docker images | grep pypowerwall | awk '{print $3}' | xargs docker rmi -f

aesculus commented 1 year ago

Working fine so closing this thread. Thanks for the help.