Shelly: drop grid energy and returnEnergy for 3-phase EM (#30534)

This commit is contained in:
premultiply 2026-06-08 12:07:18 +02:00 • committed by GitHub
parent 69e31deda0
commit bfb55dc2c4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 38 additions and 6 deletions

View file

@ -14,7 +14,7 @@ import (
// Shelly meter considering usage
type Shelly struct {
implement.Caps
shelly.Connection
conn *shelly.Connection
usage string
}
@ -45,7 +45,14 @@ func NewShellyFromConfig(other map[string]any) (api.Meter, error) {
return nil, err
}
if phases, ok := c.Connection.Generation.(shelly.Phases); ok {
// Three-phase Shelly energy meters count each phase separately (non-balanced),
// making their totals unsuitable for bidirectional grid metering.
if !(c.usage == "grid" && c.conn.IsThreePhase()) {
implement.Has(c, implement.MeterEnergy(c.conn.TotalEnergy))
implement.Has(c, implement.MeterReturnEnergy(c.conn.ReturnEnergy))
}
if phases, ok := c.conn.Generation.(shelly.Phases); ok {
implement.Has(c, implement.PhaseVoltages(phases.Voltages))
implement.Has(c, implement.PhaseCurrents(phases.Currents))
implement.Has(c, implement.PhasePowers(phases.Powers))
@ -61,9 +68,9 @@ func NewShelly(uri, user, password, usage string, channel int, cache time.Durati
return nil, err
}
c := &Shelly{
Caps: implement.New(),
Connection: *conn,
usage: usage,
Caps: implement.New(),
conn: conn,
usage: usage,
}
return c, nil
}
@ -72,7 +79,7 @@ var _ api.Meter = (*Shelly)(nil)
// CurrentPower implements the api.Meter interface
func (c *Shelly) CurrentPower() (float64, error) {
power, err := c.Connection.CurrentPower()
power, err := c.conn.CurrentPower()
if err != nil {
return 0, err
}

View file

@ -18,6 +18,7 @@ type Generation interface {
api.Meter
api.MeterEnergy
api.MeterReturnEnergy
IsThreePhase() bool
}
type Phases interface {

View file

@ -144,6 +144,12 @@ func (c *gen1) ReturnEnergy() (float64, error) {
return c.energy(energy) / 1000, nil
}
// IsThreePhase reports whether the device is a three-phase energy meter.
func (c *gen1) IsThreePhase() bool {
res, err := c.status.Get()
return err == nil && len(res.EMeters) == 3
}
// gen1Energy in kWh
func (c *gen1) energy(energy float64) float64 {
// Gen 1 Shelly EM devices are providing Watt hours, Gen 1 Shelly PM devices are providing Watt minutes

View file

@ -332,6 +332,11 @@ func (c *gen2) hasEMEndpoint() bool {
return c.hasMethod("EM.GetStatus")
}
// IsThreePhase reports whether the device is a three-phase energy meter
func (c *gen2) IsThreePhase() bool {
return c.hasEMEndpoint()
}
// Gen2+ models using EM1.GetStatus endpoint for power and EM1Data.GetStatus for energy
// https://shelly-api-docs.shelly.cloud/gen2/ComponentsAndServices/EM1#em1getstatus-example
// https://shelly-api-docs.shelly.cloud/gen2/ComponentsAndServices/EM1Data#em1datagetstatus-example

View file

@ -3,6 +3,9 @@ products:
- brand: Shelly
description:
generic: 3EM (Gen.1)
# 3-phase Shelly EM devices count each phase's energy separately (non-balanced),
# so the totals are unsuitable for bidirectional grid metering. Energy and
# returnEnergy are therefore omitted for grid usage (see #29727).
params:
- name: usage
choice: ["grid", "pv", "charge"]
@ -20,11 +23,18 @@ render: |
source: http
uri: {{ include "uri" . }}/status
jq: .emeters | map(.power) | add
{{- if ne .usage "grid" }}
energy:
source: http
uri: {{ include "uri" . }}/status
jq: .emeters | map(.total) | add
scale: 0.001
returnenergy:
source: http
uri: {{ include "uri" . }}/status
jq: .emeters | map(.total_returned) | add
scale: 0.001
{{- end }}
currents:
- source: http
uri: {{ include "uri" . }}/emeter/0

View file

@ -2,6 +2,9 @@ template: shelly-pro-3em
products:
- { brand: Shelly, description: { generic: Pro 3 EM } }
- { brand: Shelly, description: { generic: 3 EM-63T/W Gen3 } }
# 3-phase Shelly EM devices count each phase's energy separately (non-balanced),
# so the totals are unsuitable for bidirectional grid metering. The shelly meter
# suppresses energy and returnEnergy for grid usage (see #29727).
params:
- name: usage
choice: ["grid", "pv", "charge"]