Repository: evcc-io/evcc
Pull request #4928 (2022-10-24 15:06:59)

Varta: fix register type
Fix https://github.com/evcc-io/evcc/issues/4893


Patch:
diff --git a/core/loadpoint.go b/core/loadpoint.go
index 3812a678..f2164782 100644
--- a/core/loadpoint.go
+++ b/core/loadpoint.go
@@ -449,8 +449,6 @@ func (lp *LoadPoint) evVehicleDisconnectHandler() {
 	lp.publish("chargedEnergy", lp.chargedEnergy)
 	lp.publish("connectedDuration", lp.clock.Since(lp.connectedTime))
 
-	lp.pushEvent(evVehicleDisconnect)
-
 	// remove charger vehicle id and stop potential detection
 	lp.setVehicleIdentifier("")
 	lp.stopVehicleDetection()
@@ -1047,6 +1045,33 @@ func (lp *LoadPoint) vehicleOdometer() {
 	}
 }
 
+// statusEvents converts the observed charger status change into a logical sequence of events
+func statusEvents(prevStatus, status api.ChargeStatus) []string {
+	res := make([]string, 0, 2)
+
+	// changed from A - connected
+	if prevStatus == api.StatusA || (status != api.StatusA && prevStatus == api.StatusNone) {
+		res = append(res, evVehicleConnect)
+	}
+
+	// changed to C - start charging
+	if status == api.StatusC {
+		res = append(res, evChargeStart)
+	}
+
+	// changed from C - stop charging
+	if prevStatus == api.StatusC {
+		res = append(res, evChargeStop)
+	}
+
+	// changed to A - disconnected
+	if status == api.StatusA {
+		res = append(res, evVehicleDisconnect)
+	}
+
+	return res
+}
+
 // updateChargerStatus updates charger status and detects car connected/disconnected events
 func (lp *LoadPoint) updateChargerStatus() error {
 	status, err := lp.charger.Status()
@@ -1059,26 +1084,18 @@ func (lp *LoadPoint) updateChargerStatus() error {
 	if prevStatus := lp.GetStatus(); status != prevStatus {
 		lp.setStatus(status)
 
-		// changed to A - disconnected - don't send on startup
-		if status == api.StatusA && prevStatus != api.StatusNone {
-			lp.bus.Publish(evVehicleDisconnect)
-		}
+		for _, ev := range statusEvents(prevStatus, status) {
+			lp.bus.Publish(ev)
 
-		// changed to B - connected - don't send on startup
-		if status == api.StatusB && prevStatus != api.StatusC {
+			// send connect/disconnect events except during startup
 			if prevStatus != api.StatusNone {
-				// send connected message if not startup
-				lp.pushEvent(evVehicleConnect)
+				switch ev {
+				case evVehicleConnect:
+					lp.pushEvent(evVehicleConnect)
+				case evVehicleDisconnect:
+					lp.pushEvent(evVehicleDisconnect)
+				}
 			}
-
-			lp.bus.Publish(evVehicleConnect)
-		}
-
-		// changed to C - start/stop charging cycle - handle before disconnect to update energy
-		if lp.charging() {
-			lp.bus.Publish(evChargeStart)
-		} else if prevStatus == api.StatusC {
-			lp.bus.Publish(evChargeStop)
 		}
 
 		// update whenever there is a state change
diff --git a/templates/definition/meter/varta-energiespeicher-battery-only.yaml b/templates/definition/meter/varta-energiespeicher-battery-only.yaml
index 26265711..318efa40 100644
--- a/templates/definition/meter/varta-energiespeicher-battery-only.yaml
+++ b/templates/definition/meter/varta-energiespeicher-battery-only.yaml
@@ -20,7 +20,7 @@ render: |
     id: 255
     register:
       address: 1078 # grid power
-      type: input
+      type: holding
       decode: int16
     scale: -1
   {{- end }}
@@ -28,7 +28,7 @@ render: |
     id: 255
     register:
       address: 1066 # active power
-      type: input
+      type: holding
       decode: int16
     scale: -1
   soc:
@@ -37,6 +37,6 @@ render: |
     id: 255
     register:
       address: 1068 # SOC
-      type: input
+      type: holding
       decode: int16
   {{- end }}
diff --git a/templates/definition/meter/varta-energiespeicher.yaml b/templates/definition/meter/varta-energiespeicher.yaml
index 5d8b3cfe..7b6339bc 100644
--- a/templates/definition/meter/varta-energiespeicher.yaml
+++ b/templates/definition/meter/varta-energiespeicher.yaml
@@ -20,7 +20,7 @@ render: |
     id: 255
     register:
       address: 1078 # grid power
-      type: input
+      type: holding
       decode: int16
     scale: -1
   {{- end }}
@@ -28,14 +28,14 @@ render: |
     id: 255
     register:
       address: 1102 # PV-sensor power
-      type: input
+      type: holding
       decode: uint16
   {{- end }}
   {{- if eq .usage "battery" }}
     id: 255
     register:
       address: 1066 # active power
-      type: input
+      type: holding
       decode: int16
     scale: -1
   soc:
@@ -44,6 +44,6 @@ render: |
     id: 255
     register:
       address: 1068 # SOC
-      type: input
+      type: holding
       decode: int16
   {{- end }}


Test patch:
diff --git a/core/loadpoint_status_test.go b/core/loadpoint_status_test.go
new file mode 100644
index 00000000..55e7980e
--- /dev/null
+++ b/core/loadpoint_status_test.go
@@ -0,0 +1,33 @@
+package core
+
+import (
+	"testing"
+
+	"github.com/evcc-io/evcc/api"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestStatusEvents(t *testing.T) {
+	tc := []struct {
+		from, to api.ChargeStatus
+		events   []string
+	}{
+		{api.StatusNone, api.StatusA, []string{evVehicleDisconnect}},
+		{api.StatusNone, api.StatusB, []string{evVehicleConnect}},
+		{api.StatusNone, api.StatusC, []string{evVehicleConnect, evChargeStart}},
+
+		{api.StatusA, api.StatusB, []string{evVehicleConnect}},
+		{api.StatusA, api.StatusC, []string{evVehicleConnect, evChargeStart}},
+
+		{api.StatusB, api.StatusA, []string{evVehicleDisconnect}},
+		{api.StatusB, api.StatusC, []string{evChargeStart}},
+
+		{api.StatusC, api.StatusA, []string{evChargeStop, evVehicleDisconnect}},
+		{api.StatusC, api.StatusB, []string{evChargeStop}},
+	}
+
+	for _, tc := range tc {
+		ev := statusEvents(tc.from, tc.to)
+		assert.Equalf(t, tc.events, ev, "from %s to %s got: %v", tc.from, tc.to, ev)
+	}
+}
diff --git a/core/loadpoint_test.go b/core/loadpoint_test.go
index c15c5f3d..e4caf6ad 100644
--- a/core/loadpoint_test.go
+++ b/core/loadpoint_test.go
@@ -418,6 +418,7 @@ func TestDisableAndEnableAtTargetSoC(t *testing.T) {
 
 	lp.enabled = true
 	lp.chargeCurrent = float64(minA)
+	lp.status = api.StatusC
 
 	t.Log("charging below soc target")
 	vehicle.EXPECT().SoC().Return(85.0, nil)