Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
pdeliot opened this issue Oct 20, 2024 · 28 comments
Open

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

pdeliot opened this issue Oct 20, 2024 · 28 comments
Labels
devices Specific device support

Comments

@pdeliot
Copy link

pdeliot commented Oct 20, 2024

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
Copy link
Author

pdeliot commented Oct 20, 2024

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

@andig andig added the devices Specific device support label Oct 20, 2024
@VolkerK62
Copy link
Contributor

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

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
Copy link
Author

pdeliot commented Oct 20, 2024

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 ?

@VolkerK62
Copy link
Contributor

But powers is wNow and not rmsCurrent.

@pdeliot
Copy link
Author

pdeliot commented Oct 21, 2024

But powers is wNow and not rmsCurrent.

Yes! Fixed.

@pdeliot
Copy link
Author

pdeliot commented Oct 21, 2024

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?

@VolkerK62
Copy link
Contributor

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
Copy link
Author

pdeliot commented Oct 23, 2024

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
Copy link
Contributor

VolkerK62 commented Oct 23, 2024

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
Copy link
Author

pdeliot commented Oct 23, 2024

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
Copy link
Contributor

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
Copy link
Author

pdeliot commented Oct 24, 2024

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
Copy link
Author

pdeliot commented Oct 24, 2024

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

@ivoks
Copy link
Contributor

ivoks commented Oct 24, 2024

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
Copy link
Author

pdeliot commented Oct 24, 2024

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

@ivoks
Copy link
Contributor

ivoks commented Oct 25, 2024

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

@pdeliot
Copy link
Author

pdeliot commented Oct 25, 2024

enphase.yaml.gz
The template for test

@ivoks
Copy link
Contributor

ivoks commented Oct 25, 2024

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
Copy link
Author

pdeliot commented Oct 26, 2024

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
Copy link
Author

pdeliot commented Nov 1, 2024

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

@BeneWilh
Copy link

BeneWilh commented Nov 1, 2024

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

@ivoks
Copy link
Contributor

ivoks commented Nov 1, 2024

@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
Copy link
Contributor

ivoks commented Nov 1, 2024

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

@pdeliot
Copy link
Author

pdeliot commented Nov 6, 2024

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

@pdeliot
Copy link
Author

pdeliot commented Nov 10, 2024

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

@ivoks
Copy link
Contributor

ivoks commented Nov 11, 2024

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

@pdeliot
Copy link
Author

pdeliot commented Nov 11, 2024

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

@ivoks
Copy link
Contributor

ivoks commented Nov 11, 2024

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
devices Specific device support
Projects
None yet
Development

No branches or pull requests

5 participants