From 551e7ac0bd7921af9c43772ae0af847d5b7c11ed Mon Sep 17 00:00:00 2001 From: Vincent Bakker Date: Mon, 27 Apr 2026 18:32:51 +0200 Subject: [PATCH] Stegen Smart EVSE: make charge mode configurable, fix status & keep-alive (#29290) --- charger/smart-evse.go | 42 ++++++++++---------- templates/definition/charger/smart-evse.yaml | 13 +++++- 2 files changed, 32 insertions(+), 23 deletions(-) diff --git a/charger/smart-evse.go b/charger/smart-evse.go index 1f93831b5..285cee3a6 100644 --- a/charger/smart-evse.go +++ b/charger/smart-evse.go @@ -36,6 +36,7 @@ type SmartEVSE3 struct { *request.Helper uri string curr int64 + mode int apiG util.Cacheable[smartEvseRestSettings] } @@ -110,10 +111,12 @@ func init() { // NewSmartEVSE3FromConfig creates a SmartEVSE-3.5 REST charger from generic config func NewSmartEVSE3FromConfig(other map[string]any) (api.Charger, error) { cc := struct { - URI string - Cache time.Duration + URI string + Cache time.Duration + ChargeMode string }{ - Cache: time.Second, + Cache: time.Second, + ChargeMode: "normal", } if err := util.DecodeOther(other, &cc); err != nil { @@ -124,17 +127,27 @@ func NewSmartEVSE3FromConfig(other map[string]any) (api.Charger, error) { return nil, fmt.Errorf("missing uri") } - return NewSmartEVSE3(cc.URI, cc.Cache) + mode := smartEvse3ModeNormal + if cc.ChargeMode == "smart" { + mode = smartEvse3ModeSmart + } + + return NewSmartEVSE3(cc.URI, cc.Cache, mode) } // NewSmartEVSE3 creates a new SmartEVSE-3.5 REST charger -func NewSmartEVSE3(uri string, cache time.Duration) (api.Charger, error) { +func NewSmartEVSE3(uri string, cache time.Duration, mode int) (api.Charger, error) { log := util.NewLogger("smart-evse") wb := &SmartEVSE3{ Helper: request.NewHelper(log), uri: strings.TrimRight(util.DefaultScheme(uri, "http"), "/"), curr: 60, // 6 A in 1/10 A + mode: mode, + } + + wb.Helper.Client.Transport = &http.Transport{ + DisableKeepAlives: true, } wb.apiG = util.ResettableCached(func() (smartEvseRestSettings, error) { @@ -149,13 +162,6 @@ func NewSmartEVSE3(uri string, cache time.Duration) (api.Charger, error) { return nil, err } - // force NORMAL mode so override_current takes effect - if res.ModeID != smartEvse3ModeNormal { - if err := wb.setMode(smartEvse3ModeNormal); err != nil { - return nil, err - } - } - // decorate optional EV meter if configured in SmartEVSE var currentPower, totalEnergy func() (float64, error) var currents func() (float64, float64, float64, error) @@ -221,17 +227,11 @@ func (wb *SmartEVSE3) Status() (api.ChargeStatus, error) { // state IDs from SmartEVSE firmware (main_c.h) switch res.Evse.StateID { - case 0: // STATE_A - return api.StatusA, nil - case 1, 4, 5, 8, 9, 11, 12, 13, 14: - // STATE_B, STATE_COMM_B, STATE_COMM_B_OK, STATE_ACTSTART, STATE_B1, - // STATE_MODEM_REQUEST, STATE_MODEM_WAIT, STATE_MODEM_DONE, STATE_MODEM_DENIED - return api.StatusB, nil case 2, 3, 6, 7, 10: // STATE_C, STATE_D, STATE_COMM_C, STATE_COMM_C_OK, STATE_C1 return api.StatusC, nil default: - return api.StatusNone, fmt.Errorf("invalid state: %d (%s)", res.Evse.StateID, res.Evse.State) + return api.StatusB, nil } } @@ -262,8 +262,8 @@ func (wb *SmartEVSE3) Enable(enable bool) error { } if enable { - if res.ModeID != smartEvse3ModeNormal { - return wb.setMode(smartEvse3ModeNormal) + if res.ModeID != wb.mode { + return wb.setMode(wb.mode) } return nil } diff --git a/templates/definition/charger/smart-evse.yaml b/templates/definition/charger/smart-evse.yaml index 60b52e2a2..3cf804944 100644 --- a/templates/definition/charger/smart-evse.yaml +++ b/templates/definition/charger/smart-evse.yaml @@ -8,16 +8,25 @@ requirements: description: de: | Anbindung über die REST API der Smart Evse Firmware (FW >= 3.6.0). - evcc setzt das Gerät in den NORMAL Modus und steuert den Ladestrom über `override_current`. + evcc setzt das Gerät in den konfigurierten Modus und steuert den Ladestrom über `override_current`. en: | Uses the REST API of the Smart Evse firmware (FW >= 3.6.0). - evcc puts the device into NORMAL mode and controls the charge current via `override_current`. + evcc puts the device into the configured mode and controls the charge current via `override_current`. params: - name: host - name: cache default: 1s advanced: true + - name: chargeMode + default: normal + advanced: true + type: choice + choice: ["normal", "smart"] + description: + en: Charge mode + de: Lademodus render: | type: smart-evse uri: http://{{ .host }} cache: {{ .cache }} + chargeMode: {{ .chargeMode }}