From 4d5f374576586c906afc15326c050219f5b72418 Mon Sep 17 00:00:00 2001 From: Manuel Haag <50206431+helijunky@users.noreply.github.com> Date: Sat, 17 Jan 2026 15:17:26 +0100 Subject: [PATCH] Zaptec: add mA regulation and improve phase switching (#26573) --- charger/zaptec.go | 53 +++++++++++++++++++++++++++++++---------- charger/zaptec/types.go | 18 +++++++------- 2 files changed, 49 insertions(+), 22 deletions(-) diff --git a/charger/zaptec.go b/charger/zaptec.go index a58673c6e..5f5002992 100644 --- a/charger/zaptec.go +++ b/charger/zaptec.go @@ -22,6 +22,7 @@ import ( "encoding/json" "errors" "fmt" + "math" "net/http" "sort" "time" @@ -44,7 +45,7 @@ type Zaptec struct { log *util.Logger statusG util.Cacheable[zaptec.StateResponse] instance zaptec.Charger - maxCurrent int + maxCurrent float64 version int enabled bool priority bool @@ -266,9 +267,16 @@ func (c *Zaptec) sessionPriority(session string, data zaptec.SessionPriority) er // MaxCurrent implements the api.Charger interface func (c *Zaptec) MaxCurrent(current int64) error { - curr := int(current) + return c.MaxCurrentMillis(float64(current)) +} + +var _ api.ChargerEx = (*Zaptec)(nil) + +// MaxCurrentMillis implements the api.ChargerEx interface +func (c *Zaptec) MaxCurrentMillis(current float64) error { + current = math.Round(current*10) / 10 data := zaptec.Update{ - MaxChargeCurrent: &curr, + MaxChargeCurrent: ¤t, } return c.chargerUpdate(data) @@ -319,21 +327,39 @@ func (c *Zaptec) Currents() (float64, float64, float64, error) { // phases1p3p implements the api.PhaseSwitcher interface func (c *Zaptec) phases1p3p(phases int) error { - err := c.switchPhases(phases) - if err != nil || !c.priority { + if err := c.switchPhases(phases); err != nil { return err } - // priority configured - data := zaptec.SessionPriority{ - PrioritizedPhases: &phases, - } - res, err := c.statusG.Get() if err != nil { return err } + // adjust the current by +/- 0.1A; otherwise, the phase change will not happen + current, err := res.ObservationByID(zaptec.ChargerMaxCurrent).Float64() + if err != nil { + return err + } + + current -= 0.1 + if current < 6 { + current += 0.2 + } + + if err := c.MaxCurrentMillis(current); err != nil { + return err + } + + if !c.priority { + return nil + } + + // priority configured + data := zaptec.SessionPriority{ + PrioritizedPhases: &phases, + } + if session := res.ObservationByID(zaptec.SessionIdentifier); session != nil { return c.sessionPriority(session.ValueAsString, data) } @@ -346,10 +372,11 @@ func (c *Zaptec) switchPhases(phases int) error { data := zaptec.Update{ MaxChargePhases: &phases, } + return c.chargerUpdate(data) } - var zero int + var zero float64 data := zaptec.UpdateInstallation{ AvailableCurrentPhase1: &c.maxCurrent, AvailableCurrentPhase2: &zero, @@ -382,7 +409,7 @@ func (c *Zaptec) Identify() (string, error) { return "", nil } -func (c *Zaptec) getInstallationMaxCurrent() (int, error) { +func (c *Zaptec) getInstallationMaxCurrent() (float64, error) { var res zaptec.Installation uri := fmt.Sprintf("%s/api/installation/%s", zaptec.ApiURL, c.instance.InstallationId) @@ -390,7 +417,7 @@ func (c *Zaptec) getInstallationMaxCurrent() (int, error) { return 0, err } - return int(res.MaxCurrent), nil + return res.MaxCurrent, nil } func (c *Zaptec) installationUpdate(data zaptec.UpdateInstallation) error { diff --git a/charger/zaptec/types.go b/charger/zaptec/types.go index d6984a76b..51a11ec8c 100644 --- a/charger/zaptec/types.go +++ b/charger/zaptec/types.go @@ -72,12 +72,12 @@ func (o *Observation) Float64() (float64, error) { } type Update struct { - MaxChargeCurrent *int `json:"maxChargeCurrent,omitempty"` - MaxChargePhases *int `json:"maxChargePhases,omitempty"` - MinChargeCurrent *int `json:"minChargeCurrent,omitempty"` - OfflineChargeCurrent *int `json:"offlineChargeCurrent,omitempty"` - OfflineChargePhase *int `json:"offlineChargePhase,omitempty"` - MeterValueInterval *int `json:"meterValueInterval,omitempty"` + MaxChargeCurrent *float64 `json:"maxChargeCurrent,omitempty"` + MaxChargePhases *int `json:"maxChargePhases,omitempty"` + MinChargeCurrent *float64 `json:"minChargeCurrent,omitempty"` + OfflineChargeCurrent *float64 `json:"offlineChargeCurrent,omitempty"` + OfflineChargePhase *int `json:"offlineChargePhase,omitempty"` + MeterValueInterval *int `json:"meterValueInterval,omitempty"` } type SessionPriority struct { @@ -90,9 +90,9 @@ type Installation struct { } type UpdateInstallation struct { - AvailableCurrentPhase1 *int `json:"availableCurrentPhase1,omitempty"` - AvailableCurrentPhase2 *int `json:"availableCurrentPhase2,omitempty"` - AvailableCurrentPhase3 *int `json:"availableCurrentPhase3,omitempty"` + AvailableCurrentPhase1 *float64 `json:"availableCurrentPhase1,omitempty"` + AvailableCurrentPhase2 *float64 `json:"availableCurrentPhase2,omitempty"` + AvailableCurrentPhase3 *float64 `json:"availableCurrentPhase3,omitempty"` } type CapabilitiesResponse struct {