evcc-io / evcc

Sonne tanken ☀️🚘
https://evcc.io
MIT License
3.57k stars 660 forks source link

support phase currents, and three-phase with enphase envoy #16744

Open pdeliot opened 2 weeks ago

pdeliot commented 2 weeks ago

To use enphase template for circuit, phase current is required.

This information information is available for single and tree-phase.

Three-phase support is also required (for me ;-) )...

Attached sample file with Tree-phase.

envoy.json Below a little sample extract of available data: { "consumption": [ { "type": "eim", "activeCount": 1, "measurementType": "net-consumption", "readingTime": 1729414585, "wNow": 5364.339, "whLifetime": 48631628.574, "lines": [ { "wNow": 452.054, "whLifetime": 20136453.749, "varhLeadLifetime": 5727861.458, }, { "wNow": -98.144, "whLifetime": 1634255.145, "varhLeadLifetime": 4811478.811, }, { "wNow": 5010.429, "whLifetime": 26860919.68, "varhLeadLifetime": 1345115.396, } ] } ] }

pdeliot commented 2 weeks ago

I can try to work on it if you can point me a sample template for tree-phase and/or phases currents...

VolkerK62 commented 2 weeks ago

here you can see an example, how to add currents to a template https://github.com/evcc-io/evcc/blob/master/templates/definition/meter/shelly-3em.yaml

it should be the same syntax as for power https://github.com/evcc-io/evcc/blob/27e45a2b31861acb9be891b0fa3c29e325677f81/templates/definition/meter/enphase.yaml#L23

the jq should be jq: .consumption[] | select(.measurementType == "net-consumption").lines[0].rmsCurrent

where lines[0] = phase 1 lines[1] = phase 2 lines[2] = phase 3

pdeliot commented 2 weeks ago

Thanks,

I've started a first implementation that looks to work.

` powers:

Is it expected/better to have 2 version of the template? Or a parameter to define 1 or 3 phases? Or it will deal automatically with error on phase 1 and 2 ?

VolkerK62 commented 2 weeks ago

But powers is wNow and not rmsCurrent.

pdeliot commented 2 weeks ago

But powers is wNow and not rmsCurrent.

Yes! Fixed.

pdeliot commented 2 weeks ago

Now I have severall questions

VolkerK62 commented 2 weeks ago

Understand how to deal with single and three phase definision

How does the JSON für single-phase looks like?

Is it possible to use ONE query for several indicators (to avoid querying once per value. All the values are in the returned json)?

Not sure, but I don´t think so.

How can I push the contribution?

create a PR. Best way would be, to modify the actual template, if it is working under all circumstances

pdeliot commented 2 weeks ago

How does the JSON für single-phase looks like?

I'm working on a solution with optional 'phases" parameter default 1 for implemetation.

But maybe other ways exists...

On phase can be retrieved this fashion (simplified):

{ "type": "eim", "activeCount": 1, "measurementType": "net-consumption", "readingTime": 1729537922, "wNow": 725.998, "whLifetime": 81596.841, "rmsCurrent": 3.771, "rmsVoltage": 241.879, "pwrFactor": 0.8, "lines": [ { "wNow": 725.998, "whLifetime": 81596.841, "rmsCurrent": 3.771, "rmsVoltage": 241.879, "pwrFactor": 0.8, } ] }

And Three-pahse this way (simplified):

{ "type": "eim", "activeCount": 1, "measurementType": "net-consumption", "readingTime": 1729684620, "wNow": 4640.513, "whLifetime": 48824472.782, "pwrFactor": 0.83, "lines": [ { "wNow": 253.166, "whLifetime": 20186173.813, "rmsCurrent": 2.875, "rmsVoltage": 245.513, "pwrFactor": 0.36, }, { "wNow": -495.77, "whLifetime": 1644809.589, "rmsCurrent": -2.447, "rmsVoltage": 242.702, "pwrFactor": -1.0, }, { "wNow": 4883.117, "whLifetime": 26993489.38, "rmsCurrent": 22.817, "rmsVoltage": 239.245, "pwrFactor": 0.89, "whToday": 0, } ] }

VolkerK62 commented 1 week ago

I'm working on a solution with optional 'phases" parameter default 1 for implemetation.

in that case it is breaking change for all 3p configuration Best way would be a kind of automatic detection.

Don´t know, what would be the best way for that. One possibility ist the sum of voltages below 300 = 1p above 300 = 3p But I am sure, this would be the solution of an amateur 😃

pdeliot commented 1 week ago

It should not break existing 3p configuration, because the template today is treating 3p as 1p. Then if no change is done on "evcc.yaml" to add the "phases' with default '1' parameter value, nothing will change (or just new feature becoming available).

It is possible to detect, but I must work to understand how to use calculations in yaml ;-) Maybe counting rows (then phases) in JSON. But it may be too late, because the template is already parssed and loaded, before any measure to comme back.

I'm fighting a little bit with 'currents'... Is is supported for 1p installations?

I do not see how to define 'currents' (or maybe 'current' ?) for only one phase.

VolkerK62 commented 1 week ago

I do not see how to define 'currents' (or maybe 'current' ?) for only one phase.

it must be currents and it must be three In case of 1p, you must set set the Phases 2 and 3 to 0

I tried the following with a one phase shelly and it works:

  currents:
    - source: http
      uri: 192.168.178.88/status
      jq: .meters[0].power
    - source: http
      uri: 192.168.178.88/status
      jq: if .meters[1].power == null then 0 else .meters[1].power end
    - source: http
      uri: 192.168.178.88/status
      jq: if .meters[2].power == null then 0 else .meters[2].power end
pdeliot commented 1 week ago

I've followed this implementation and it looks working.. test in progress.

Doe exists a documentation on "how to contribute" .. how to create/select a branch and create a PR ?

pdeliot commented 1 week ago

Does 'powers' and 'currents' can be negative (in case of injection) ? Or should be set to 0 when negative?

ivoks commented 1 week ago

There's a twist here... They could be negative, positive, 0 and even totally wrong. Currents are available only when CTs are used. If no CTs are installed, Envoy uses data coming from inverters, and that means that currents are just false, as they are not collected from the inverters.

I have an enphase that doesn't have CTs and reads power and energy correctly, but currents are wrong. If you have a patch, I'd be glad to test it in my environment.

pdeliot commented 1 week ago

I've written a new template with 'currents', but only tested on my installation with CTs.

ivoks commented 1 week ago

Feel free to attach it and I can test it in my setup.

pdeliot commented 1 week ago

enphase.yaml.gz The template for test

ivoks commented 1 week ago

Thank you! I've ran the test and I'm quite sure that the PV part is not correct. By looking at the consumption, you are getting info about consumption and not production. PV should tell you what the production of the PV is.

If you turn this into '.production[] | select(.measurementType == "production")', then for all three phases on my system it would look like this: $ curl http://172.16.12.43/production.json?details=1 2>/dev/null | jq 'if .production[] | select(.measurementType == "production").lines[1].wNow == null then 0 else .production[] | select(.measurementType == "production").lines[0].wNow end' 0.0 $ curl http://172.16.12.43/production.json?details=1 2>/dev/null | jq 'if .production[] | select(.measurementType == "production").lines[1].wNow == null then 0 else .production[] | select(.measurementType == "production").lines[1].wNow end' -0.688 $ curl http://172.16.12.43/production.json?details=1 2>/dev/null | jq 'if .production[] | select(.measurementType == "production").lines[1].wNow == null then 0 else .production[] | select(.measurementType == "production").lines[2].wNow end' -1.291

And these are all wrong. Maybe this would be a better approach:

$ curl http://172.16.12.43/production.json?details=1 2>/dev/null | jq 'if .production[] | select(.measurementType == "production").activeCount >= 1 then .production[] | select(.measurementType == "production").lines[0].wNow else empty end' $ curl http://172.16.12.43/production.json?details=1 2>/dev/null | jq 'if .production[] | select(.measurementType == "production").activeCount >= 1 then .production[] | select(.measurementType == "production").lines[1].wNow else empty end' $ curl http://172.16.12.43/production.json?details=1 2>/dev/null | jq 'if .production[] | select(.measurementType == "production").activeCount >= 1 then .production[] | select(.measurementType == "production").lines[2].wNow else empty end' $

First if statement checks number of active CTs/phases. Those without CTs should have 0 activeCount (as I do). And then, instead of returning 0 (which is not really correct), it would probably be better to return empty value, so that evcc knows that the data is not valid. And then you can apply the same approach for currents:

$ curl http://172.16.12.43/production.json?details=1 2>/dev/null | jq 'if .production[] | select(.measurementType == "production").activeCount >= 1 then .production[] | select(.measurementType == "production").lines[0].rmsCurrent else empty end' $ curl http://172.16.12.43/production.json?details=1 2>/dev/null | jq 'if .production[] | select(.measurementType == "production").activeCount >= 1 then .production[] | select(.measurementType == "production").lines[1].rmsCurrent else empty end' $ curl http://172.16.12.43/production.json?details=1 2>/dev/null | jq 'if .production[] | select(.measurementType == "production").activeCount >= 1 then .production[] | select(.measurementType == "production").lines[2].rmsCurrent else empty end' $

and voltages:

$ curl http://172.16.12.43/production.json?details=1 2>/dev/null | jq 'if .production[] | select(.measurementType == "production").activeCount >= 1 then .production[] | select(.measurementType == "production").lines[0].rmsVoltage else empty end' $ curl http://172.16.12.43/production.json?details=1 2>/dev/null | jq 'if .production[] | select(.measurementType == "production").activeCount >= 1 then .production[] | select(.measurementType == "production").lines[1].rmsVoltage else empty end' $ curl http://172.16.12.43/production.json?details=1 2>/dev/null | jq 'if .production[] | select(.measurementType == "production").activeCount >= 1 then .production[] | select(.measurementType == "production").lines[2].rmsVoltage else empty end' $

Can you check if these give you correct values in your environment?

[EDIT: fixed activeCount check. I thought the number represents number of active phases, but in case of CTs it seems it basically a bool for 'enabled/disabled', while for inverters it provides the number of active inverters.]

pdeliot commented 1 week ago

Hi Ante,

I have few time to work on this during this week-end .

But your suggestion looks better than my implementation. I will test it and get back to you.

It may also apply to grid.

pdeliot commented 5 days ago

I'm currently testing a version based on your suggestions Ante. enphase.yaml.gz Maybe you can try it at your side.

BeneWilh commented 4 days ago

could you give a hint where to put the enphase.yaml on a linux distribution? thx

ivoks commented 4 days ago

@pdeliot building right now and I'll give it a try. @BeneWilh evcc is a golang app, so it's statically compiled and any changes need to be made in source tree. On top of that templates are built into the resulting binary.

ivoks commented 4 days ago

It's looking good. However, it's nighttime right now, so I'll be able to confirm tomorrow when some sunlight hits the panels.