From 9239cfdc8db9291757ec38f7554b8f23ae46cb7b Mon Sep 17 00:00:00 2001 From: u222650 Date: Wed, 21 May 2025 10:14:20 +0200 Subject: [PATCH 1/5] #21078 update doc for zaptec chargers. set capabilitier for go2 and pro to "rfid" and "1p3p" and add info how to change settings to let evcc control the phase switch --- templates/definition/charger/zaptec-go2.yaml | 35 ++++++++++++++++++++ templates/definition/charger/zaptec-pro.yaml | 20 +++++++++++ templates/definition/charger/zaptec.yaml | 6 ---- 3 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 templates/definition/charger/zaptec-go2.yaml create mode 100644 templates/definition/charger/zaptec-pro.yaml diff --git a/templates/definition/charger/zaptec-go2.yaml b/templates/definition/charger/zaptec-go2.yaml new file mode 100644 index 0000000000..17d8d6f987 --- /dev/null +++ b/templates/definition/charger/zaptec-go2.yaml @@ -0,0 +1,35 @@ +template: zaptec-go2 +products: + - brand: Zaptec + description: + generic: Go 2 +capabilities: [ "rfid", "1p3p" ] +requirements: + evcc: [ "sponsorship" ] + description: + de: | + Im Zaptec-Portal (Installationen -> Einstellungen -> Leistungsregelung) müssen für die Zaptec Go 2 folgende Einstellungen vorgenommen werden: + + en: | + In the Zaptec portal (Installations -> Settings -> Power Management), the following settings must be configured for the Zaptec Go 2: + +params: + - name: id + help: + de: Wallbox ID + en: Charger ID + - name: user + - name: password +render: | + type: zaptec + id: {{ .id }} + user: {{ .user }} + password: '{{ .password }}' diff --git a/templates/definition/charger/zaptec-pro.yaml b/templates/definition/charger/zaptec-pro.yaml new file mode 100644 index 0000000000..aacde73ddd --- /dev/null +++ b/templates/definition/charger/zaptec-pro.yaml @@ -0,0 +1,20 @@ +template: zaptec-pro +products: + - brand: Zaptec + description: + generic: Pro +capabilities: ["rfid", "1p3p"] +requirements: + evcc: ["sponsorship"] +params: + - name: id + help: + de: Wallbox ID + en: Charger ID + - name: user + - name: password +render: | + type: zaptec + id: {{ .id }} + user: {{ .user }} + password: '{{ .password }}' diff --git a/templates/definition/charger/zaptec.yaml b/templates/definition/charger/zaptec.yaml index 84d0628058..fd5d3ba160 100644 --- a/templates/definition/charger/zaptec.yaml +++ b/templates/definition/charger/zaptec.yaml @@ -3,12 +3,6 @@ products: - brand: Zaptec description: generic: Go - - brand: Zaptec - description: - generic: Go 2 - - brand: Zaptec - description: - generic: Pro capabilities: ["rfid"] requirements: evcc: ["sponsorship"] From 92548a1ac287f43b03811ef5f1d2fb857b34075e Mon Sep 17 00:00:00 2001 From: u222650 Date: Wed, 21 May 2025 13:29:02 +0200 Subject: [PATCH 2/5] #21078 format yaml --- templates/definition/charger/zaptec-go2.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/definition/charger/zaptec-go2.yaml b/templates/definition/charger/zaptec-go2.yaml index 17d8d6f987..e6417df9a2 100644 --- a/templates/definition/charger/zaptec-go2.yaml +++ b/templates/definition/charger/zaptec-go2.yaml @@ -3,9 +3,9 @@ products: - brand: Zaptec description: generic: Go 2 -capabilities: [ "rfid", "1p3p" ] +capabilities: ["rfid", "1p3p"] requirements: - evcc: [ "sponsorship" ] + evcc: ["sponsorship"] description: de: | Im Zaptec-Portal (Installationen -> Einstellungen -> Leistungsregelung) müssen für die Zaptec Go 2 folgende Einstellungen vorgenommen werden: From c13ec434f2088c589c47fafb6af068ecba471469 Mon Sep 17 00:00:00 2001 From: u222650 Date: Fri, 30 May 2025 09:40:00 +0200 Subject: [PATCH 3/5] #21078 keep phases low until evcc charge begins. --- charger/zaptec.go | 102 +++++++++++++++++++++++++++++++++++----- charger/zaptec/types.go | 7 ++- 2 files changed, 96 insertions(+), 13 deletions(-) diff --git a/charger/zaptec.go b/charger/zaptec.go index 4e9c61d68b..39992164cd 100644 --- a/charger/zaptec.go +++ b/charger/zaptec.go @@ -41,13 +41,14 @@ import ( // Zaptec charger implementation type Zaptec struct { *request.Helper - log *util.Logger - statusG util.Cacheable[zaptec.StateResponse] - instance zaptec.Charger - maxCurrent int - version int - enabled bool - priority bool + log *util.Logger + statusG util.Cacheable[zaptec.StateResponse] + instance zaptec.Charger + maxCurrent int + version int + enabled bool + desiredPhases int + priority bool } func init() { @@ -145,6 +146,11 @@ func NewZaptec(user, password, id string, priority bool, cache time.Duration) (a if err != nil { return nil, err } + + err = c.disableAllPhases() + if err != nil { + return nil, err + } return c, nil } @@ -188,6 +194,14 @@ func (c *Zaptec) Status() (api.ChargeStatus, error) { switch i, err := res.ObservationByID(zaptec.ChargerOperationMode).Int(); i { case zaptec.OpModeDisconnected: + //When the plug is disconnected during charging, c.Enable(false) is not invoked. + if c.version == zaptec.ZaptecGo2 && c.enabled { + err = c.disableAllPhases() + if err != nil { + return api.StatusA, err + } + } + c.enabled = false return api.StatusA, err case zaptec.OpModeConnectedRequesting, zaptec.OpModeConnectedFinished: return api.StatusB, err @@ -213,6 +227,34 @@ func (c *Zaptec) Enable(enable bool) error { if enable { cmd = zaptec.CmdResumeCharging } + if c.version == zaptec.ZaptecGo2 { + phases, err := c.configuredPhases() + + if enable && phases == 0 { + err = c.Phases1p3p(c.desiredPhases) + if err != nil { + return err + } + } + if !enable { + err = c.disableAllPhases() + if err != nil { + return err + } + } + + res, err := c.statusG.Get() + if err != nil { + return err + } + + // when the plug is connected the wallbox is charging an additional call to enable leads to a 500 error + isWallBoxOff := res.ObservationByID(zaptec.FinalStopActive).Bool() + if enable && !isWallBoxOff { + c.enabled = true + return nil + } + } uri := fmt.Sprintf("%s/api/chargers/%s/sendCommand/%d", zaptec.ApiURL, c.instance.Id, cmd) @@ -252,6 +294,15 @@ func (c *Zaptec) sessionPriority(session string, data zaptec.SessionPriority) er // MaxCurrent implements the api.Charger interface func (c *Zaptec) MaxCurrent(current int64) error { + if c.version == zaptec.ZaptecGo2 { + phases, err := c.configuredPhases() + if err != nil { + return err + } + if current > 0 && phases == 0 { + return c.switchPhases(c.desiredPhases) + } + } curr := int(current) data := zaptec.Update{ MaxChargeCurrent: &curr, @@ -307,11 +358,14 @@ var _ api.PhaseSwitcher = (*Zaptec)(nil) // Phases1p3p implements the api.ChargePhases interface func (c *Zaptec) Phases1p3p(phases int) error { - err := c.switchPhases(phases) - if err != nil || !c.priority { - return err - } + c.desiredPhases = phases + if (c.version == zaptec.ZaptecGo2 && c.enabled) || c.version != zaptec.ZaptecGo2 { + err := c.switchPhases(phases) + if err != nil || !c.priority { + return err + } + } // priority configured data := zaptec.SessionPriority{ PrioritizedPhases: &phases, @@ -329,6 +383,16 @@ func (c *Zaptec) Phases1p3p(phases int) error { return errors.New("unknown session") } +func (c *Zaptec) disableAllPhases() error { + var zero int + data := zaptec.UpdateInstallation{ + AvailableCurrentPhase1: &zero, + AvailableCurrentPhase2: &zero, + AvailableCurrentPhase3: &zero, + } + return c.installationUpdate(data) +} + func (c *Zaptec) switchPhases(phases int) error { if c.version != zaptec.ZaptecGo2 { data := zaptec.Update{ @@ -370,6 +434,22 @@ func (c *Zaptec) Identify() (string, error) { return "", nil } +func (c *Zaptec) configuredPhases() (int, error) { + var res zaptec.Installation + + uri := fmt.Sprintf("%s/api/installation/%s", zaptec.ApiURL, c.instance.InstallationId) + if err := c.GetJSON(uri, &res); err != nil { + return 0, err + } + if res.AvailableCurrentPhase1 == 0 && res.AvailableCurrentPhase2 == 0 && res.AvailableCurrentPhase3 == 0 { + return 0, nil + } + if res.AvailableCurrentPhase1 > 0 && res.AvailableCurrentPhase2 > 0 && res.AvailableCurrentPhase3 > 0 { + return 3, nil + } + return 1, nil +} + func (c *Zaptec) getMaxCurrent() (int, error) { var res zaptec.Installation diff --git a/charger/zaptec/types.go b/charger/zaptec/types.go index d6984a76bd..fe42a0fcf4 100644 --- a/charger/zaptec/types.go +++ b/charger/zaptec/types.go @@ -85,8 +85,11 @@ type SessionPriority struct { } type Installation struct { - Id string `json:"id"` - MaxCurrent float64 `json:"maxCurrent"` + Id string `json:"id"` + MaxCurrent float64 `json:"maxCurrent"` + AvailableCurrentPhase1 float64 `json:"availableCurrentPhase1,omitempty"` + AvailableCurrentPhase2 float64 `json:"availableCurrentPhase2,omitempty"` + AvailableCurrentPhase3 float64 `json:"availableCurrentPhase3,omitempty"` } type UpdateInstallation struct { From 58dfab897f2f62b3cbca85f103cc084015844190 Mon Sep 17 00:00:00 2001 From: u222650 Date: Fri, 30 May 2025 10:04:22 +0200 Subject: [PATCH 4/5] #21078 revert unwanted changes on this branch --- charger/zaptec.go | 102 +++++----------------------------------- charger/zaptec/types.go | 7 +-- 2 files changed, 13 insertions(+), 96 deletions(-) diff --git a/charger/zaptec.go b/charger/zaptec.go index 39992164cd..4e9c61d68b 100644 --- a/charger/zaptec.go +++ b/charger/zaptec.go @@ -41,14 +41,13 @@ import ( // Zaptec charger implementation type Zaptec struct { *request.Helper - log *util.Logger - statusG util.Cacheable[zaptec.StateResponse] - instance zaptec.Charger - maxCurrent int - version int - enabled bool - desiredPhases int - priority bool + log *util.Logger + statusG util.Cacheable[zaptec.StateResponse] + instance zaptec.Charger + maxCurrent int + version int + enabled bool + priority bool } func init() { @@ -146,11 +145,6 @@ func NewZaptec(user, password, id string, priority bool, cache time.Duration) (a if err != nil { return nil, err } - - err = c.disableAllPhases() - if err != nil { - return nil, err - } return c, nil } @@ -194,14 +188,6 @@ func (c *Zaptec) Status() (api.ChargeStatus, error) { switch i, err := res.ObservationByID(zaptec.ChargerOperationMode).Int(); i { case zaptec.OpModeDisconnected: - //When the plug is disconnected during charging, c.Enable(false) is not invoked. - if c.version == zaptec.ZaptecGo2 && c.enabled { - err = c.disableAllPhases() - if err != nil { - return api.StatusA, err - } - } - c.enabled = false return api.StatusA, err case zaptec.OpModeConnectedRequesting, zaptec.OpModeConnectedFinished: return api.StatusB, err @@ -227,34 +213,6 @@ func (c *Zaptec) Enable(enable bool) error { if enable { cmd = zaptec.CmdResumeCharging } - if c.version == zaptec.ZaptecGo2 { - phases, err := c.configuredPhases() - - if enable && phases == 0 { - err = c.Phases1p3p(c.desiredPhases) - if err != nil { - return err - } - } - if !enable { - err = c.disableAllPhases() - if err != nil { - return err - } - } - - res, err := c.statusG.Get() - if err != nil { - return err - } - - // when the plug is connected the wallbox is charging an additional call to enable leads to a 500 error - isWallBoxOff := res.ObservationByID(zaptec.FinalStopActive).Bool() - if enable && !isWallBoxOff { - c.enabled = true - return nil - } - } uri := fmt.Sprintf("%s/api/chargers/%s/sendCommand/%d", zaptec.ApiURL, c.instance.Id, cmd) @@ -294,15 +252,6 @@ func (c *Zaptec) sessionPriority(session string, data zaptec.SessionPriority) er // MaxCurrent implements the api.Charger interface func (c *Zaptec) MaxCurrent(current int64) error { - if c.version == zaptec.ZaptecGo2 { - phases, err := c.configuredPhases() - if err != nil { - return err - } - if current > 0 && phases == 0 { - return c.switchPhases(c.desiredPhases) - } - } curr := int(current) data := zaptec.Update{ MaxChargeCurrent: &curr, @@ -358,14 +307,11 @@ var _ api.PhaseSwitcher = (*Zaptec)(nil) // Phases1p3p implements the api.ChargePhases interface func (c *Zaptec) Phases1p3p(phases int) error { - c.desiredPhases = phases - if (c.version == zaptec.ZaptecGo2 && c.enabled) || c.version != zaptec.ZaptecGo2 { - err := c.switchPhases(phases) - - if err != nil || !c.priority { - return err - } + err := c.switchPhases(phases) + if err != nil || !c.priority { + return err } + // priority configured data := zaptec.SessionPriority{ PrioritizedPhases: &phases, @@ -383,16 +329,6 @@ func (c *Zaptec) Phases1p3p(phases int) error { return errors.New("unknown session") } -func (c *Zaptec) disableAllPhases() error { - var zero int - data := zaptec.UpdateInstallation{ - AvailableCurrentPhase1: &zero, - AvailableCurrentPhase2: &zero, - AvailableCurrentPhase3: &zero, - } - return c.installationUpdate(data) -} - func (c *Zaptec) switchPhases(phases int) error { if c.version != zaptec.ZaptecGo2 { data := zaptec.Update{ @@ -434,22 +370,6 @@ func (c *Zaptec) Identify() (string, error) { return "", nil } -func (c *Zaptec) configuredPhases() (int, error) { - var res zaptec.Installation - - uri := fmt.Sprintf("%s/api/installation/%s", zaptec.ApiURL, c.instance.InstallationId) - if err := c.GetJSON(uri, &res); err != nil { - return 0, err - } - if res.AvailableCurrentPhase1 == 0 && res.AvailableCurrentPhase2 == 0 && res.AvailableCurrentPhase3 == 0 { - return 0, nil - } - if res.AvailableCurrentPhase1 > 0 && res.AvailableCurrentPhase2 > 0 && res.AvailableCurrentPhase3 > 0 { - return 3, nil - } - return 1, nil -} - func (c *Zaptec) getMaxCurrent() (int, error) { var res zaptec.Installation diff --git a/charger/zaptec/types.go b/charger/zaptec/types.go index fe42a0fcf4..d6984a76bd 100644 --- a/charger/zaptec/types.go +++ b/charger/zaptec/types.go @@ -85,11 +85,8 @@ type SessionPriority struct { } type Installation struct { - Id string `json:"id"` - MaxCurrent float64 `json:"maxCurrent"` - AvailableCurrentPhase1 float64 `json:"availableCurrentPhase1,omitempty"` - AvailableCurrentPhase2 float64 `json:"availableCurrentPhase2,omitempty"` - AvailableCurrentPhase3 float64 `json:"availableCurrentPhase3,omitempty"` + Id string `json:"id"` + MaxCurrent float64 `json:"maxCurrent"` } type UpdateInstallation struct { From bc5ccba7b9ba030cd694c481317fb8510454fa0b Mon Sep 17 00:00:00 2001 From: u222650 Date: Fri, 30 May 2025 18:11:12 +0200 Subject: [PATCH 5/5] #21078 markdown is the preferred way here - so migrate li to - --- templates/definition/charger/zaptec-go2.yaml | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/templates/definition/charger/zaptec-go2.yaml b/templates/definition/charger/zaptec-go2.yaml index e6417df9a2..d6985f2384 100644 --- a/templates/definition/charger/zaptec-go2.yaml +++ b/templates/definition/charger/zaptec-go2.yaml @@ -9,18 +9,14 @@ requirements: description: de: | Im Zaptec-Portal (Installationen -> Einstellungen -> Leistungsregelung) müssen für die Zaptec Go 2 folgende Einstellungen vorgenommen werden: -
    -
  • Aktiviere "Ladegeräten erlauben, zum dreiphasigen Laden zurückkehren"
  • -
  • Setze "Erlaubte Wechsel vor der Festlegung auf einphasiges Laden" auf das Maximum von 20
  • -
  • Setze "Wechsel von drei- auf einphasiges Laden" auf 1 A
  • -
+ - Aktiviere "Ladegeräten erlauben, zum dreiphasigen Laden zurückkehren" + - Setze "Erlaubte Wechsel vor der Festlegung auf einphasiges Laden" auf das Maximum von 20 + - Setze "Wechsel von drei- auf einphasiges Laden" auf 1 A en: | In the Zaptec portal (Installations -> Settings -> Power Management), the following settings must be configured for the Zaptec Go 2: -
    -
  • Enable "Allow chargers to return to three-phase charging"
  • -
  • Set "Allowed switches before locking to single-phase charging" to the maximum of 20
  • -
  • Set "Switch from three-phase to single-phase charging" to 1 A
  • -
+ - Enable "Allow chargers to return to three-phase charging" + - Set "Allowed switches before locking to single-phase charging" to the maximum of 20 + - Set "Switch from three-phase to single-phase charging" to 1 A params: - name: id help: