Repository: evcc-io/evcc (go)

Issue:
shelly-1pm ohne Messwerte
### Describe the bug

Gennanten Shelly habe ich seit einiger Zeit im Einsatz.
Die Verbindung ist laut GUI in Ordnung, dennoch werden keine Messwerte erkannt.

<img width="313" alt="Image" src="https://github.com/user-attachments/assets/e2ce7265-c26e-4ce6-8959-3aa7a597cd63" />

### Steps to reproduce

1.
2.
3.
...


### Configuration details

```yaml
Config über GUI
```

### Log details

```text
[site ] DEBUG 2025/03/24 10:41:48 battery 1 power: -1580W
[pv2 ] TRACE 2025/03/24 10:41:48 modbus: send 01 4d 00 00 00 06 05 04 00 0a 00 01
[shelly] TRACE 2025/03/24 10:41:48 {"id":0,"on":false,"src":"evcc","method":"Shelly.GetStatus"} -- {"ble":{},"bthome":{"errors":["bluetooth_disabled"]},"cloud":{"connected":true},"em1:0":{"id":0,"current":1.449,"voltage":227.4,"act_power":-327.8,"aprt_power":330.1,"pf":0.99,"freq":50.0,"calibration":"factory"},"em1:1":{"id":1,"current":0.436,"voltage":227.4,"act_power":-40.9,"aprt_power":99.4,"pf":0.41,"freq":50.0,"calibration":"factory"},"em1data:0":{"id":0,"total_act_energy":1264.15,"total_act_ret_energy":144786.81},"em1data:1":{"id":1,"total_act_energy":48002.83,"total_act_ret_energy":33240.93},"eth":{"ip":null},"modbus":{},"mqtt":{"connected":false},"switch:0":{"id":0, "source":"HTTP_in", "output":false,"temperature":{"tC":46.4, "tF":115.5}},"sys":{"mac":"08F9E0E8AF2C","restart_required":false,"time":"10:41","unixtime":1742809308,"uptime":3671356,"ram_size":249732,"ram_free":108068,"fs_size":524288,"fs_free":188416,"cfg_rev":12,"kvs_rev":0,"schedule_rev":1,"webhook_rev":0,"available_updates":{"beta":{"version":"1.5.1-beta2"}},"reset_reason":3},"wifi":{"sta_ip":"192.168.1.120","status":"got ip","ssid":"Spaetzlewerk","rssi":-61},"ws":{"connected":false}}
[site ] DEBUG 2025/03/24 10:41:48 pv 2 power: 0W
[shelly] TRACE 2025/03/24 10:41:48 POST http://192.168.1.120/rpc/Shelly.GetStatus
[pv2 ] TRACE 2025/03/24 10:41:48 modbus: recv 01 4d 00 00 00 05 05 04 02 03 f4
[pv2 ] TRACE 2025/03/24 10:41:48 modbus: send 01 4e 00 00 00 06 05 04 00 0b 00 01
[shelly] TRACE 2025/03/24 10:41:48 {"id":0,"on":false,"src":"evcc","method":"Shelly.GetStatus"} -- {"ble":{},"bthome":{"errors":["bluetooth_disabled"]},"cloud":{"connected":true},"em1:0":{"id":0,"current":1.449,"voltage":227.4,"act_power":-327.8,"aprt_power":330.1,"pf":0.99,"freq":50.0,"calibration":"factory"},"em1:1":{"id":1,"current":0.436,"voltage":227.4,"act_power":-40.9,"aprt_power":99.4,"pf":0.41,"freq":50.0,"calibration":"factory"},"em1data:0":{"id":0,"total_act_energy":1264.15,"total_act_ret_energy":144786.81},"em1data:1":{"id":1,"total_act_energy":48002.83,"total_act_ret_energy":33240.93},"eth":{"ip":null},"modbus":{},"mqtt":{"connected":false},"switch:0":{"id":0, "source":"HTTP_in", "output":false,"temperature":{"tC":46.4, "tF":115.5}},"sys":{"mac":"08F9E0E8AF2C","restart_required":false,"time":"10:41","unixtime":1742809308,"uptime":3671357,"ram_size":249796,"ram_free":109448,"fs_size":524288,"fs_free":188416,"cfg_rev":12,"kvs_rev":0,"schedule_rev":1,"webhook_rev":0,"available_updates":{"beta":{"version":"1.5.1-beta2"}},"reset_reason":3},"wifi":{"sta_ip":"192.168.1.120","status":"got ip","ssid":"Spaetzlewerk","rssi":-61},"ws":{"connected":false}}
[pv2 ] TRACE 2025/03/24 10:41:48 modbus: recv 01 4e 00 00 00 05 05 04 02 03 9f
[site ] DEBUG 2025/03/24 10:41:48 pv 1 power: 1939W
[site ] DEBUG 2025/03/24 10:41:48 battery 1 soc: 57%
[pv2 ] TRACE 2025/03/24 10:41:48 modbus: send 01 50 00 00 00 06 05 04 00 94 00 02
[pv2 ] TRACE 2025/03/24 10:41:48 modbus: recv 01 50 00 00 00 07 05 04 04 7f b2 00 06
[site ] DEBUG 2025/03/24 10:41:48 pv power: 1939W
[site ] DEBUG 2025/03/24 10:41:48 battery has priority at soc 57% (< 70%)
[site ] DEBUG 2025/03/24 10:41:48 site power: -321W
[site ] DEBUG 2025/03/24 10:42:02 ----
[site ] DEBUG 2025/03/24 10:42:02 grid power: -430W
[shelly] TRACE 2025/03/24 10:42:02 POST http://192.168.1.120/rpc/Shelly.GetStatus
[pv2 ] TRACE 2025/03/24 10:42:03 modbus: send 01 53 00 00 00 06 05 04 00 0a 00 01
[shelly] TRACE 2025/03/24 10:42:03 POST http://192.168.1.120/rpc/Shelly.GetStatus
[pv2 ] TRACE 2025/03/24 10:42:03 modbus: recv 01 53 00 00 00 05 05 04 02 03 f7
[site ] DEBUG 2025/03/24 10:42:03 battery 1 power: -1582W
[pv2 ] TRACE 2025/03/24 10:42:03 modbus: send 01 55 00 00 00 06 05 04 00 0b 00 01
[pv2 ] TRACE 2025/03/24 10:42:03 modbus: recv 01 55 00 00 00 05 05 04 02 03 9b
[site ] DEBUG 2025/03/24 10:42:03 pv 1 power: 1938W
[pv2 ] TRACE 2025/03/24 10:42:03 modbus: send 01 56 00 00 00 06 05 04 00 94 00 02
[pv2 ] TRACE 2025/03/24 10:42:03 modbus: recv 01 56 00 00 00 07 05 04 04 7f b2 00 06
[site ] DEBUG 2025/03/24 10:42:03 battery 1 soc: 57%
[shelly] TRACE 2025/03/24 10:42:03 {"id":1,"on":false,"src":"evcc","method":"Shelly.GetStatus"} -- {"ble":{},"bthome":{"errors":["bluetooth_disabled"]},"cloud":{"connected":true},"em1:0":{"id":0,"current":1.473,"voltage":226.9,"act_power":-332.2,"aprt_power":335.0,"pf":0.99,"freq":50.0,"calibration":"factory"},"em1:1":{"id":1,"current":0.428,"voltage":227.0,"act_power":-38.5,"aprt_power":97.4,"pf":0.38,"freq":50.0,"calibration":"factory"},"em1data:0":{"id":0,"total_act_energy":1264.15,"total_act_ret_energy":144792.28},"em1data:1":{"id":1,"total_act_energy":48002.83,"total_act_ret_energy":33241.59},"eth":{"ip":null},"modbus":{},"mqtt":{"connected":false},"switch:0":{"id":0, "source":"HTTP_in", "output":false,"temperature":{"tC":46.4, "tF":115.5}},"sys":{"mac":"08F9E0E8AF2C","restart_required":false,"time":"10:42","unixtime":1742809323,"uptime":3671372,"ram_size":249692,"ram_free":107568,"fs_size":524288,"fs_free":188416,"cfg_rev":12,"kvs_rev":0,"schedule_rev":1,"webhook_rev":0,"available_updates":{"beta":{"version":"1.5.1-beta2"}},"reset_reason":3},"wifi":{"sta_ip":"192.168.1.120","status":"got ip","ssid":"Spaetzlewerk","rssi":-61},"ws":{"connected":false}}
[site ] DEBUG 2025/03/24 10:42:03 pv 3 power: 0W
[shelly] TRACE 2025/03/24 10:42:03 POST http://192.168.1.120/rpc/Shelly.GetStatus
[shelly] TRACE 2025/03/24 10:42:03 {"id":0,"on":false,"src":"evcc","method":"Shelly.GetStatus"} -- {"ble":{},"bthome":{"errors":["bluetooth_disabled"]},"cloud":{"connected":true},"em1:0":{"id":0,"current":1.473,"voltage":226.9,"act_power":-332.2,"aprt_power":335.0,"pf":0.99,"freq":50.0,"calibration":"factory"},"em1:1":{"id":1,"current":0.428,"voltage":227.0,"act_power":-38.5,"aprt_power":97.4,"pf":0.38,"freq":50.0,"calibration":"factory"},"em1data:0":{"id":0,"total_act_energy":1264.15,"total_act_ret_energy":144792.28},"em1data:1":{"id":1,"total_act_energy":48002.83,"total_act_ret_energy":33241.59},"eth":{"ip":null},"modbus":{},"mqtt":{"connected":false},"switch:0":{"id":0, "source":"HTTP_in", "output":false,"temperature":{"tC":46.4, "tF":115.5}},"sys":{"mac":"08F9E0E8AF2C","restart_required":false,"time":"10:42","unixtime":1742809323,"uptime":3671372,"ram_size":249612,"ram_free":106052,"fs_size":524288,"fs_free":188416,"cfg_rev":12,"kvs_rev":0,"schedule_rev":1,"webhook_rev":0,"available_updates":{"beta":{"version":"1.5.1-beta2"}},"reset_reason":3},"wifi":{"sta_ip":"192.168.1.120","status":"got ip","ssid":"Spaetzlewerk","rssi":-61},"ws":{"connected":false}}
[site ] DEBUG 2025/03/24 10:42:03 pv 2 power: 0W
[shelly] TRACE 2025/03/24 10:42:03 POST http://192.168.1.120/rpc/Shelly.GetStatus
[shelly] TRACE 2025/03/24 10:42:03 {"id":1,"on":false,"src":"evcc","method":"Shelly.GetStatus"} -- {"ble":{},"bthome":{"errors":["bluetooth_disabled"]},"cloud":{"connected":true},"em1:0":{"id":0,"current":1.473,"voltage":226.9,"act_power":-332.2,"aprt_power":335.0,"pf":0.99,"freq":50.0,"calibration":"factory"},"em1:1":{"id":1,"current":0.428,"voltage":227.0,"act_power":-38.5,"aprt_power":97.4,"pf":0.38,"freq":50.0,"calibration":"factory"},"em1data:0":{"id":0,"total_act_energy":1264.15,"total_act_ret_energy":144792.28},"em1data:1":{"id":1,"total_act_energy":48002.83,"total_act_ret_energy":33241.59},"eth":{"ip":null},"modbus":{},"mqtt":{"connected":false},"switch:0":{"id":0, "source":"HTTP_in", "output":false,"temperature":{"tC":46.4, "tF":115.5}},"sys":{"mac":"08F9E0E8AF2C","restart_required":false,"time":"10:42","unixtime":1742809323,"uptime":3671372,"ram_size":249660,"ram_free":107080,"fs_size":524288,"fs_free":188416,"cfg_rev":12,"kvs_rev":0,"schedule_rev":1,"webhook_rev":0,"available_updates":{"beta":{"version":"1.5.1-beta2"}},"reset_reason":3},"wifi":{"sta_ip":"192.168.1.120","status":"got ip","ssid":"Spaetzlewerk","rssi":-61},"ws":{"connected":false}}
[shelly] TRACE 2025/03/24 10:42:03 {"id":0,"on":false,"src":"evcc","method":"Shelly.GetStatus"} -- {"ble":{},"bthome":{"errors":["bluetooth_disabled"]},"cloud":{"connected":true},"em1:0":{"id":0,"current":1.473,"voltage":226.9,"act_power":-332.2,"aprt_power":335.0,"pf":0.99,"freq":50.0,"calibration":"factory"},"em1:1":{"id":1,"current":0.428,"voltage":227.0,"act_power":-38.5,"aprt_power":97.4,"pf":0.38,"freq":50.0,"calibration":"factory"},"em1data:0":{"id":0,"total_act_energy":1264.15,"total_act_ret_energy":144792.28},"em1data:1":{"id":1,"total_act_energy":48002.83,"total_act_ret_energy":33241.59},"eth":{"ip":null},"modbus":{},"mqtt":{"connected":false},"switch:0":{"id":0, "source":"HTTP_in", "output":false,"temperature":{"tC":46.4, "tF":115.5}},"sys":{"mac":"08F9E0E8AF2C","restart_required":false,"time":"10:42","unixtime":1742809323,"uptime":3671372,"ram_size":249680,"ram_free":107492,"fs_size":524288,"fs_free":188416,"cfg_rev":12,"kvs_rev":0,"schedule_rev":1,"webhook_rev":0,"available_updates":{"beta":{"version":"1.5.1-beta2"}},"reset_reason":3},"wifi":{"sta_ip":"192.168.1.120","status":"got ip","ssid":"Spaetzlewerk","rssi":-61},"ws":{"connected":false}}
[site ] DEBUG 2025/03/24 10:42:03 pv power: 1938W
[site ] DEBUG 2025/03/24 10:42:03 battery has priority at soc 57% (< 70%)
[site ] DEBUG 2025/03/24 10:42:03 site power: -230W
```

### What type of operating system or environment does evcc run on?

Linux

### External automation

- [x] I have made sure that no external automation like HomeAssistant or Node-RED is active or accessing any of the mentioned devices when this issue occurs.

### Nightly build

- [x] I have verified that the issue is reproducible with the latest nightly build

### Version

v0.201.1

Pull request description:
Shelly: Simplify/Standardize Pro EM readings
Simplification and consolidation of Shelly Pro EM device responses.

Fixes #20060 

Shelly Pro EM-50 meter readings are provided now. Solution should also cover other Pro EM devices:

Pro EM-50 meter test config and results based on shared responses of @SolarPower2024:
```yaml
meters:
- name: shelly-pro-em-50-0-pv
  type: template
  template: shelly-1pm
  usage: pv
  host: localhost:8080 # IP-Adresse oder Hostname
  channel: 0 # Optional

- name: shelly-pro-em-50-0-charge
  type: template
  template: shelly-1pm
  usage: charge
  host: localhost:8080 # IP-Adresse oder Hostname
  channel: 0 # Optional

- name: shelly-pro-em-50-1-pv
  type: template
  template: shelly-1pm
  usage: pv
  host: localhost:8080 # IP-Adresse oder Hostname
  channel: 1 # Optional

- name: shelly-pro-em-50-1-charge
  type: template
  template: shelly-1pm
  usage: charge
  host: localhost:8080 # IP-Adresse oder Hostname
  channel: 1 # Optional
```

```bash
thierolm@LAPTOP-KQMMVN3H:~/git-repos/evcc$ ./evcc -c ./evcc_shelly_test.yaml -l debug meter
[main  ] INFO 2025/03/26 20:43:24 evcc 0.202.0 (adad05283)
[main  ] INFO 2025/03/26 20:43:24 using config file: ./evcc_shelly_test.yaml
[db    ] INFO 2025/03/26 20:43:24 using sqlite database: /home/thierolm/.evcc/evcc.db
shelly-pro-em-50-1-charge
-------------------------
Power:  38W
Energy: 14.8kWh

shelly-pro-em-50-0-pv
---------------------
Power:  332W
Energy: -143.5kWh

shelly-pro-em-50-0-charge
-------------------------
Power:  332W
Energy: -143.5kWh

shelly-pro-em-50-1-pv
---------------------
Power:  38W
Energy: 14.8kWh
```

Patch:
diff --git a/core/circuit/circuit.go b/core/circuit/circuit.go
index 76fd821f..051fef08 100644
--- a/core/circuit/circuit.go
+++ b/core/circuit/circuit.go
@@ -7,6 +7,7 @@ import (
 	"sync"
 	"time"
 
+	"github.com/cenkalti/backoff/v4"
 	"github.com/evcc-io/evcc/api"
 	"github.com/evcc-io/evcc/plugin"
 	"github.com/evcc-io/evcc/util"
@@ -234,7 +235,7 @@ func (c *Circuit) overloadOnError(t time.Time, val *float64) {
 }
 
 func (c *Circuit) updateMeters() error {
-	if f, err := c.meter.CurrentPower(); err == nil {
+	if f, err := backoff.RetryWithData(c.meter.CurrentPower, bo()); err == nil {
 		c.power = f
 		c.powerUpdated = time.Now()
 	} else {
@@ -243,6 +244,16 @@ func (c *Circuit) updateMeters() error {
 	}
 
 	if phaseMeter, ok := c.meter.(api.PhaseCurrents); ok {
+		var i1, i2, i3 float64
+		if err := backoff.Retry(func() error {
+			var err error
+			i1, i2, i3, err = phaseMeter.Currents()
+			return err
+		}, bo()); err != nil {
+			c.overloadOnError(c.currentUpdated, &c.current)
+			return fmt.Errorf("circuit currents: %w", err)
+		}
+
 		var p1, p2, p3 float64
 		if phaseMeter, ok := c.meter.(api.PhasePowers); ok {
 			var err error // phases needed for signed currents
@@ -251,13 +262,8 @@ func (c *Circuit) updateMeters() error {
 			}
 		}
 
-		if i1, i2, i3, err := phaseMeter.Currents(); err == nil {
-			c.current = max(util.SignFromPower(i1, p1), util.SignFromPower(i2, p2), util.SignFromPower(i3, p3))
-			c.currentUpdated = time.Now()
-		} else {
-			c.overloadOnError(c.currentUpdated, &c.current)
-			return fmt.Errorf("circuit currents: %w", err)
-		}
+		c.current = max(util.SignFromPower(i1, p1), util.SignFromPower(i2, p2), util.SignFromPower(i3, p3))
+		c.currentUpdated = time.Now()
 	}
 
 	return nil
diff --git a/core/circuit/helper.go b/core/circuit/helper.go
new file mode 100644
index 00000000..77c88c8b
--- /dev/null
+++ b/core/circuit/helper.go
@@ -0,0 +1,12 @@
+package circuit
+
+import (
+	"time"
+
+	"github.com/cenkalti/backoff/v4"
+)
+
+// bo returns an exponential backoff for reading meter power quickly
+func bo() *backoff.ExponentialBackOff {
+	return backoff.NewExponentialBackOff(backoff.WithInitialInterval(20*time.Millisecond), backoff.WithMaxElapsedTime(time.Second))
+}
diff --git a/meter/shelly/energymeter.go b/meter/shelly/energymeter.go
index ccb25cb5..47a70ac7 100644
--- a/meter/shelly/energymeter.go
+++ b/meter/shelly/energymeter.go
@@ -16,7 +16,7 @@ func NewEnergyMeter(conn *Connection) *EnergyMeter {
 
 // CurrentPower implements the api.Meter interface
 func (sh *EnergyMeter) CurrentPower() (float64, error) {
-	var res Gen2EmStatusResponse
+	var res Gen2StatusResponse
 	if err := sh.Connection.execGen2Cmd("EM.GetStatus", false, &res); err != nil {
 		return 0, err
 	}
@@ -38,7 +38,7 @@ var _ api.PhaseCurrents = (*EnergyMeter)(nil)
 
 // Currents implements the api.PhaseCurrents interface
 func (sh *EnergyMeter) Currents() (float64, float64, float64, error) {
-	var res Gen2EmStatusResponse
+	var res Gen2StatusResponse
 	if err := sh.Connection.execGen2Cmd("EM.GetStatus", false, &res); err != nil {
 		return 0, 0, 0, err
 	}
@@ -50,7 +50,7 @@ var _ api.PhaseVoltages = (*EnergyMeter)(nil)
 
 // Voltages implements the api.PhaseVoltages interface
 func (sh *EnergyMeter) Voltages() (float64, float64, float64, error) {
-	var res Gen2EmStatusResponse
+	var res Gen2StatusResponse
 	if err := sh.Connection.execGen2Cmd("EM.GetStatus", false, &res); err != nil {
 		return 0, 0, 0, err
 	}
@@ -62,7 +62,7 @@ var _ api.PhasePowers = (*EnergyMeter)(nil)
 
 // Powers implements the api.PhasePowers interface
 func (sh *EnergyMeter) Powers() (float64, float64, float64, error) {
-	var res Gen2EmStatusResponse
+	var res Gen2StatusResponse
 	if err := sh.Connection.execGen2Cmd("EM.GetStatus", false, &res); err != nil {
 		return 0, 0, 0, err
 	}
diff --git a/meter/shelly/switch.go b/meter/shelly/switch.go
index 26795a9c..59cda1a5 100644
--- a/meter/shelly/switch.go
+++ b/meter/shelly/switch.go
@@ -42,25 +42,18 @@ func (sh *Switch) CurrentPower() (float64, error) {
 		}
 
 	default:
-		var resem Gen2EmStatusResponse
 		var res Gen2StatusResponse
-		if d.app == "Pro3EM" && d.profile == "monophase" {
-			if err := d.execGen2Cmd("Shelly.GetStatus", false, &resem); err != nil {
-				return 0, err
-			}
-		} else {
-			if err := d.execGen2Cmd("Shelly.GetStatus", false, &res); err != nil {
-				return 0, err
-			}
+		if err := d.execGen2Cmd("Shelly.GetStatus", false, &res); err != nil {
+			return 0, err
 		}
 
 		switch d.channel {
 		case 1:
-			power = res.Switch1.Apower + res.Pm1.Apower + resem.Em1.ActPower
+			power = res.Switch1.Apower + res.Pm1.Apower + res.Em1.ActPower
 		case 2:
-			power = res.Switch2.Apower + res.Pm2.Apower + resem.Em2.ActPower
+			power = res.Switch2.Apower + res.Pm2.Apower + res.Em2.ActPower
 		default:
-			power = res.Switch0.Apower + res.Pm0.Apower + resem.Em0.ActPower
+			power = res.Switch0.Apower + res.Pm0.Apower + res.Em0.ActPower
 		}
 	}
 
@@ -130,25 +123,18 @@ func (sh *Switch) TotalEnergy() (float64, error) {
 		energy = gen1Energy(d.devicetype, energy)
 
 	default:
-		var resem Gen2EmStatusResponse
 		var res Gen2StatusResponse
-		if d.app == "Pro3EM" && d.profile == "monophase" {
-			if err := d.execGen2Cmd("Shelly.GetStatus", false, &resem); err != nil {
-				return 0, err
-			}
-		} else {
-			if err := d.execGen2Cmd("Shelly.GetStatus", false, &res); err != nil {
-				return 0, err
-			}
+		if err := d.execGen2Cmd("Shelly.GetStatus", false, &res); err != nil {
+			return 0, err
 		}
 
 		switch d.channel {
 		case 1:
-			energy = res.Switch1.Aenergy.Total + res.Pm1.Aenergy.Total + resem.Em1Data.TotalActEnergy - resem.Em1Data.TotalActRetEnergy
+			energy = res.Switch1.Aenergy.Total + res.Pm1.Aenergy.Total + res.Em1Data.TotalActEnergy - res.Em1Data.TotalActRetEnergy
 		case 2:
-			energy = res.Switch2.Aenergy.Total + res.Pm2.Aenergy.Total + resem.Em2Data.TotalActEnergy - resem.Em2Data.TotalActRetEnergy
+			energy = res.Switch2.Aenergy.Total + res.Pm2.Aenergy.Total + res.Em2Data.TotalActEnergy - res.Em2Data.TotalActRetEnergy
 		default:
-			energy = res.Switch0.Aenergy.Total + res.Pm0.Aenergy.Total + resem.Em0Data.TotalActEnergy - resem.Em0Data.TotalActRetEnergy
+			energy = res.Switch0.Aenergy.Total + res.Pm0.Aenergy.Total + res.Em0Data.TotalActEnergy - res.Em0Data.TotalActRetEnergy
 		}
 	}
 
diff --git a/meter/shelly/types.go b/meter/shelly/types.go
index 5824d981..52d3d470 100644
--- a/meter/shelly/types.go
+++ b/meter/shelly/types.go
@@ -33,15 +33,6 @@ type Gen2Switch struct {
 	}
 }
 
-type Gen2StatusResponse struct {
-	Switch0 Gen2Switch `json:"switch:0"`
-	Switch1 Gen2Switch `json:"switch:1"`
-	Switch2 Gen2Switch `json:"switch:2"`
-	Pm0     Gen2Switch `json:"pm1:0"`
-	Pm1     Gen2Switch `json:"pm2:1"`
-	Pm2     Gen2Switch `json:"pm3:2"`
-}
-
 type Gen2Em struct {
 	Current  float64 `json:"current"`
 	Voltage  float64 `json:"voltage"`
@@ -53,7 +44,14 @@ type Gen2EmData struct {
 	TotalActRetEnergy float64 `json:"total_act_ret_energy"`
 }
 
-type Gen2EmStatusResponse struct {
+type Gen2StatusResponse struct {
+	Switch0 Gen2Switch `json:"switch:0"`
+	Switch1 Gen2Switch `json:"switch:1"`
+	Switch2 Gen2Switch `json:"switch:2"`
+	Pm0     Gen2Switch `json:"pm1:0"`
+	Pm1     Gen2Switch `json:"pm2:1"`
+	Pm2     Gen2Switch `json:"pm3:2"`
+	// additional shelly Pro EM meter JSON response
 	TotalPower float64    `json:"total_act_power"`
 	CurrentA   float64    `json:"a_current"`
 	CurrentB   float64    `json:"b_current"`
diff --git a/templates/definition/meter/sonnenbatterie.yaml b/templates/definition/meter/sonnenbatterie.yaml
index b0322d5c..00097d64 100644
--- a/templates/definition/meter/sonnenbatterie.yaml
+++ b/templates/definition/meter/sonnenbatterie.yaml
@@ -36,8 +36,8 @@ params:
     default: self-consumption
     advanced: true
     help:
-      de: Standardmodus für die aktive Batteriesteuerung (self-consumption oder time-of-use)
-      en: Default mode for active battery control (self-consumption or time-of-use)
+      de: Standardmodus für die aktive Batteriesteuerung
+      en: Default mode for active battery control
     usages: ["battery"]
   - name: chargepower
     default: 3300
diff --git a/templates/definition/meter/sungrow-hybrid.yaml b/templates/definition/meter/sungrow-hybrid.yaml
index 91c0aa1d..6e1e3b85 100644
--- a/templates/definition/meter/sungrow-hybrid.yaml
+++ b/templates/definition/meter/sungrow-hybrid.yaml
@@ -189,7 +189,11 @@ render: |
               decode: uint16
         # Reset max battery discharge power
         - source: const
-          value: {{- if .maxchargepower }}{{ .maxchargepower }}{{ else }} 1060 # 10.6kW, max allowed value for register {{ end }}
+          {{- if .maxchargepower }}
+          value: {{ .maxchargepower }}
+          {{- else }}
+          value: 1060 # 10.6kW, max allowed value for register
+          {{- end }}
           set:
             source: modbus
             {{- include "modbus" . | indent 10 }}
diff --git a/util/templates/documentation.tpl b/util/templates/documentation.tpl
index a9a1e51b..74a0af84 100644
--- a/util/templates/documentation.tpl
+++ b/util/templates/documentation.tpl
@@ -4,7 +4,14 @@
   - {{ . }}
   {{- end }}
   {{- $help := localize .Help | replace "\n" " " -}}
-  {{- if $help }} # {{ $help }}{{- end }}{{- if not .IsRequired }}{{ if not $help }} # {{ else }} ({{ end }}optional{{ if $help }}){{ end }}{{ end }}
+  {{- $choices := join ", " .Choice -}}
+  {{- $optional := not .IsRequired -}}
+  {{- if or $help $choices $optional }} # {{end}}
+  {{- if $help }}{{ $help }} {{end}}
+  {{- if $choices }}[{{ $choices }}] {{end}}
+  {{- if $optional }}
+    {{- if or $help  $choices }}(optional){{ else }}optional{{end }}
+  {{- end }}
 {{- end }}
 
 {{- define "header" }}


Test patch:
diff --git a/meter/shelly/types_test.go b/meter/shelly/types_test.go
index 2e4e968e..1a93e5ca 100644
--- a/meter/shelly/types_test.go
+++ b/meter/shelly/types_test.go
@@ -70,7 +70,7 @@ func TestUnmarshalGen2StatusResponse(t *testing.T) {
 
 	{
 		// Shelly Pro 3EM
-		var res Gen2EmStatusResponse
+		var res Gen2StatusResponse
 
 		jsonstr := `{"ble":{},"bthome":{"errors":["bluetooth_disabled"]},"cloud":{"connected":true},"em1:0":{"id":0,"current":3.705,"voltage":242.8,"act_power":598.9,"aprt_power":900.6,"pf":0.66,"freq":50.0,"calibration":"factory"},"em1:1":{"id":1,"current":0.194,"voltage":242.8,"act_power":0.0,"aprt_power":47.2,"pf":0.00,"freq":50.0,"calibration":"factory"},"em1:2":{"id":2,"current":0.027,"voltage":242.8,"act_power":0.0,"aprt_power":6.6,"pf":0.00,"freq":50.0,"calibration":"factory"},"em1data:0":{"id":0,"total_act_energy":3458.24,"total_act_ret_energy":1605.24},"em1data:1":{"id":1,"total_act_energy":2768.67,"total_act_ret_energy":25.49},"em1data:2":{"id":2,"total_act_energy":3.09,"total_act_ret_energy":0.71},"eth":{"ip":null},"modbus":{},"mqtt":{"connected":false},"sys":{"mac":"FCE8C0DBA850","restart_required":false,"time":"19:46","unixtime":1731404780,"uptime":563,"ram_size":247148,"ram_free":110596,"fs_size":524288,"fs_free":176128,"cfg_rev":21,"kvs_rev":0,"schedule_rev":3,"webhook_rev":1,"available_updates":{},"reset_reason":3},"temperature:0":{"id": 0,"tC":39.0, "tF":102.2},"wifi":{"sta_ip":"192.168.40.174","status":"got ip","ssid":"IoT","rssi":-67},"ws":{"connected":false}}`
 		require.NoError(t, json.Unmarshal([]byte(jsonstr), &res))
@@ -93,6 +93,26 @@ func TestUnmarshalGen2StatusResponse(t *testing.T) {
 		assert.Equal(t, 3.09, res.Em2Data.TotalActEnergy)
 		assert.Equal(t, 0.71, res.Em2Data.TotalActRetEnergy)
 	}
+
+	{
+		// Shelly Pro EM-50 channel 0 + 1
+		var res Gen2StatusResponse
+
+		jsonstr := `{"ble":{},"bthome":{"errors":["bluetooth_disabled"]},"cloud":{"connected":true},"em1:0":{"id":0,"current":1.473,"voltage":226.9,"act_power":-332.2,"aprt_power":335.0,"pf":0.99,"freq":50.0,"calibration":"factory"},"em1:1":{"id":1,"current":0.428,"voltage":227.0,"act_power":-38.5,"aprt_power":97.4,"pf":0.38,"freq":50.0,"calibration":"factory"},"em1data:0":{"id":0,"total_act_energy":1264.15,"total_act_ret_energy":144792.28},"em1data:1":{"id":1,"total_act_energy":48002.83,"total_act_ret_energy":33241.59},"eth":{"ip":null},"modbus":{},"mqtt":{"connected":false},"switch:0":{"id":0, "source":"HTTP_in", "output":false,"temperature":{"tC":46.4, "tF":115.5}},"sys":{"mac":"08F9E0E8AF2C","restart_required":false,"time":"10:42","unixtime":1742809323,"uptime":3671372,"ram_size":249680,"ram_free":107492,"fs_size":524288,"fs_free":188416,"cfg_rev":12,"kvs_rev":0,"schedule_rev":1,"webhook_rev":0,"available_updates":{"beta":{"version":"1.5.1-beta2"}},"reset_reason":3},"wifi":{"sta_ip":"192.168.1.120","status":"got ip","ssid":"Spaetzlewerk","rssi":-61},"ws":{"connected":false}}`
+		require.NoError(t, json.Unmarshal([]byte(jsonstr), &res))
+		// Channel 0 (1)
+		assert.Equal(t, -332.2, res.Em0.ActPower)
+		assert.Equal(t, 1.473, res.Em0.Current)
+		assert.Equal(t, 226.9, res.Em0.Voltage)
+		assert.Equal(t, 1264.15, res.Em0Data.TotalActEnergy)
+		assert.Equal(t, 144792.28, res.Em0Data.TotalActRetEnergy)
+		// Channel 1 (2)
+		assert.Equal(t, -38.5, res.Em1.ActPower)
+		assert.Equal(t, 0.428, res.Em1.Current)
+		assert.Equal(t, 227.0, res.Em1.Voltage)
+		assert.Equal(t, 48002.83, res.Em1Data.TotalActEnergy)
+		assert.Equal(t, 33241.59, res.Em1Data.TotalActRetEnergy)
+	}
 }
 
 // Test Shelly device info