evcc icon indicating copy to clipboard operation
evcc copied to clipboard

support phase currents, and three-phase with enphase envoy

Open pdeliot opened this issue 1 year ago • 15 comments

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 avatar Oct 20 '24 09:10 pdeliot

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

pdeliot avatar Oct 20 '24 09:10 pdeliot

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

VolkerK62 avatar Oct 20 '24 12:10 VolkerK62

Thanks,

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

powers: - source: http uri: http://{{ .host }}/production.json?details=1 {{- if .token }} auth: type: bearer password: {{ .token }} insecure: true {{- end }} jq: .consumption[] | select(.measurementType == "net-consumption").lines[0].rmsCurrent - source: http uri: http://{{ .host }}/production.json?details=1 {{- if .token }} auth: type: bearer password: {{ .token }} insecure: true {{- end }} jq: .consumption[] | select(.measurementType == "net-consumption").lines[1].rmsCurrent - source: http uri: http://{{ .host }}/production.json?details=1 {{- if .token }} auth: type: bearer password: {{ .token }} insecure: true {{- end }} jq: .consumption[] | select(.measurementType == "net-consumption").lines[2].rmsCurrent currents: - source: http uri: http://{{ .host }}/production.json?details=1 {{- if .token }} auth: type: bearer password: {{ .token }} insecure: true {{- end }} jq: .consumption[] | select(.measurementType == "net-consumption").lines[0].rmsCurrent - source: http uri: http://{{ .host }}/production.json?details=1 {{- if .token }} auth: type: bearer password: {{ .token }} insecure: true {{- end }} jq: .consumption[] | select(.measurementType == "net-consumption").lines[1].rmsCurrent - source: http uri: http://{{ .host }}/production.json?details=1 {{- if .token }} auth: type: bearer password: {{ .token }} insecure: true {{- end }} jq: .consumption[] | select(.measurementType == "net-consumption").lines[2].rmsCurrent voltages: - source: http uri: http://{{ .host }}/production.json?details=1 {{- if .token }} auth: type: bearer password: {{ .token }} insecure: true {{- end }} jq: .consumption[] | select(.measurementType == "net-consumption").lines[0].rmsVoltage - source: http uri: http://{{ .host }}/production.json?details=1 {{- if .token }} auth: type: bearer password: {{ .token }} insecure: true {{- end }} jq: .consumption[] | select(.measurementType == "net-consumption").lines[1].rmsVoltage - source: http uri: http://{{ .host }}/production.json?details=1 {{- if .token }} auth: type: bearer password: {{ .token }} insecure: true {{- end }} jq: .consumption[] | select(.measurementType == "net-consumption").lines[2].rmsVoltage Now I need to check this is working on single-phase systems.

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 ?

pdeliot avatar Oct 20 '24 17:10 pdeliot

But powers is wNow and not rmsCurrent.

VolkerK62 avatar Oct 21 '24 04:10 VolkerK62

But powers is wNow and not rmsCurrent.

Yes! Fixed.

pdeliot avatar Oct 21 '24 05:10 pdeliot

Now I have severall questions

  • Understand how to deal with single and three phase definision
  • Is it possible to use ONE query for several indicators (to avoid querying once per value. All the values are in the returned json)?
  • How can I push the contribution?

pdeliot avatar Oct 21 '24 05:10 pdeliot

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

VolkerK62 avatar Oct 21 '24 08:10 VolkerK62

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, } ] }

pdeliot avatar Oct 23 '24 11:10 pdeliot

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 😃

VolkerK62 avatar Oct 23 '24 15:10 VolkerK62

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.

pdeliot avatar Oct 23 '24 16:10 pdeliot

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

VolkerK62 avatar Oct 24 '24 04:10 VolkerK62

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 avatar Oct 24 '24 12:10 pdeliot

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

pdeliot avatar Oct 24 '24 12:10 pdeliot

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.

ivoks avatar Oct 24 '24 13:10 ivoks

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

pdeliot avatar Oct 24 '24 18:10 pdeliot

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

ivoks avatar Oct 25 '24 02:10 ivoks

enphase.yaml.gz The template for test

pdeliot avatar Oct 25 '24 07:10 pdeliot

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.]

ivoks avatar Oct 25 '24 09:10 ivoks

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 avatar Oct 26 '24 07:10 pdeliot

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

pdeliot avatar Nov 01 '24 12:11 pdeliot

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

BeneWilh avatar Nov 01 '24 18:11 BeneWilh

@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 avatar Nov 01 '24 21:11 ivoks

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

ivoks avatar Nov 01 '24 21:11 ivoks

Ok.. looks fine at my side... Now I need to understand how to make a PR...

pdeliot avatar Nov 06 '24 18:11 pdeliot

How to contribute? How to create a branch ? How to get access?

pdeliot avatar Nov 10 '24 17:11 pdeliot

@pdeliot as the link bellow the comment text area suggest, you should read contributing guidlines. As for forking, branching, and merging, it really depends on your level of expertise with git. If you have never done such a thing, it would be wise to read github docs and use github for this effort.

Good reads would be: Forking Editing Creating pull request

Evcc project is at https://github.com/evcc-io/evcc.

ivoks avatar Nov 11 '24 10:11 ivoks

No problem with git I'm fighting with it every day at work :-) . I've cloned the master branch, created a local branch, committed the change.. But I find now way to push the branch.. I'm always facing a 403...

pdeliot avatar Nov 11 '24 14:11 pdeliot

If you cloned from http, you can't push. You need to push to git (over ssh). It's easier to do it inside github web interface, if you don't have your local git (and github integration) fully configured.

ivoks avatar Nov 11 '24 14:11 ivoks