Tinkerforge: fix meter api and phase switching (BC) (#27334)

This commit is contained in:
lehmanju 2026-02-13 17:08:10 +00:00 • committed by GitHub
parent 0c1dcfc69a
commit 276316ed9b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 48 additions and 37 deletions

View file

@ -27,10 +27,10 @@ type WarpWS struct {
*request.Helper
// config
emHelper *request.Helper
pmHelper *request.Helper
log *util.Logger
uri string
emURI string
pmURI string
meterIndex uint
mu sync.RWMutex
@ -97,26 +97,27 @@ func NewWarpWSFromConfig(ctx context.Context, other map[string]any) (api.Charger
totalEnergy = wb.totalEnergy
}
// Feature: Phases
// Feature: Meters | MeterAllValues
var currents, voltages func() (float64, float64, float64, error)
if wb.hasFeature(warp.FeatureMeters) || wb.hasFeature(warp.FeatureMeterAllValues) {
currents = wb.currents
voltages = wb.voltages
}
if wb.hasFeature(warp.FeaturePhaseSwitch) && wb.emURI == "" {
wb.emURI = wb.uri
wb.emHelper = wb.Helper
// Feature: Phase Switching
if wb.hasFeature(warp.FeaturePhaseSwitch) && wb.pmURI == "" {
wb.pmURI = wb.uri
wb.pmHelper = wb.Helper
} else if cc.EnergyManagerURI != "" { // fallback to Energy Manager
wb.emURI, err = parseURI(cc.EnergyManagerURI, false)
if wb.emURI == "" {
wb.pmURI, err = parseURI(cc.EnergyManagerURI, false)
if wb.pmURI == "" {
return nil, err
} else if err != nil {
wb.log.DEBUG.Println(err)
}
wb.emHelper = request.NewHelper(wb.log)
wb.pmHelper = request.NewHelper(wb.log)
if cc.EnergyManagerUser != "" {
wb.emHelper.Client.Transport = digest.NewTransport(cc.EnergyManagerUser, cc.EnergyManagerPassword, wb.emHelper.Client.Transport)
wb.pmHelper.Client.Transport = digest.NewTransport(cc.EnergyManagerUser, cc.EnergyManagerPassword, wb.pmHelper.Client.Transport)
}
}
@ -126,12 +127,15 @@ func NewWarpWSFromConfig(ctx context.Context, other map[string]any) (api.Charger
identify = wb.identify
}
// Feature: EM
// only setup phase switching methods if power manager endpoint is set
var phases func(int) error
var getPhases func() (int, error)
if wb.pmState.ExternalControl != 1 {
phases = wb.phases1p3p
getPhases = wb.getPhases
if wb.pmURI != "" {
if res, err := wb.ensurePmState(); err == nil && res.ExternalControl != warp.ExternalControlDeactivated {
wb.pmState = res
phases = wb.phases1p3p
getPhases = wb.getPhases
}
}
// Phase Auto Switching needs to be disabled for WARP3
@ -234,6 +238,7 @@ func (w *WarpWS) handleConnection(ctx context.Context, conn *websocket.Conn) err
return err
}
w.log.TRACE.Printf("ws event %s: %s", event.Topic, event.Payload)
if err := w.handleEvent(event.Topic, event.Payload); err != nil {
w.log.ERROR.Printf("bad payload for topic %s: %v", event.Topic, err)
}
@ -258,7 +263,7 @@ func (w *WarpWS) handleEvent(topic string, payload json.RawMessage) error {
case "evse/state":
err = json.Unmarshal(payload, &w.evse.State)
case "meter/all_values":
if !slices.Contains(w.features, warp.FeatureMeters) {
if !slices.Contains(w.features, warp.FeatureMeterAllValues) || slices.Contains(w.features, warp.FeatureMeters) {
return nil
}
err = json.Unmarshal(payload, &w.meter.TmpValues)
@ -267,7 +272,7 @@ func (w *WarpWS) handleEvent(topic string, payload json.RawMessage) error {
copy(w.meter.Currents[:], w.meter.TmpValues[3:6])
}
case "meter/values":
if !slices.Contains(w.features, warp.FeatureMeters) {
if !slices.Contains(w.features, warp.FeatureMeter) || slices.Contains(w.features, warp.FeatureMeters) {
return nil
}
err = json.Unmarshal(payload, &w.meter)
@ -442,8 +447,8 @@ func (w *WarpWS) phases1p3p(phases int) error {
return fmt.Errorf("external control not available: %d", ec.ExternalControl)
}
w.mu.RLock()
em := w.emHelper
uri := fmt.Sprintf("%s/power_manager/external_control", w.emURI)
em := w.pmHelper
uri := fmt.Sprintf("%s/power_manager/external_control", w.pmURI)
w.mu.RUnlock()
req, _ := request.New(http.MethodPost, uri, request.MarshalJSON(map[string]int{"phases_wanted": phases}), request.JSONEncoding)
@ -473,8 +478,8 @@ func (w *WarpWS) getPhases() (int, error) {
func (w *WarpWS) ensurePmLowLevelState() (warp.PmLowLevelState, error) {
w.mu.RLock()
s := w.pmLowLevelState
em := w.emHelper
uri := w.emURI
em := w.pmHelper
uri := w.pmURI
w.mu.RUnlock()
if em == nil || uri == "" {
return s, nil
@ -495,11 +500,11 @@ func (w *WarpWS) ensurePmLowLevelState() (warp.PmLowLevelState, error) {
func (w *WarpWS) ensurePmState() (warp.PmState, error) {
w.mu.RLock()
s := w.pmState
em := w.emHelper
uri := w.emURI
em := w.pmHelper
uri := w.pmURI
w.mu.RUnlock()
if em == nil || uri == "" || s.ExternalControl != 0 {
if em == nil || uri == "" || s.ExternalControl != warp.ExternalControlAvailable {
return s, nil
}

View file

@ -1,14 +1,12 @@
template: tinkerforge-warp3-ws
template: tinkerforge-warp-ws
products:
- { brand: TinkerForge, description: { generic: WARP2 Smart } }
- { brand: TinkerForge, description: { generic: WARP2 Pro } }
- { brand: TinkerForge, description: { generic: WARP3 Smart } }
- { brand: TinkerForge, description: { generic: WARP3 Pro } }
capabilities: ["mA", "1p3p", "rfid"]
requirements:
description:
de: Die automatische Phasenumschaltung bei 1p Fahrzeugen muss deaktiviert sein. Siehe [docs.warp-charger.com](https://docs.warp-charger.com/docs/mqtt_http/api_reference/evse#evse_phase_auto_switch_warp3).
en: The automatic phase switching for 1p vehicles must be deactivated. See [docs.warp-charger.com](https://docs.warp-charger.com/docs/mqtt_http/api_reference/evse#evse_phase_auto_switch_warp3).
de: Die WARP-eigene automatische Phasenumschaltung wird von EVCC beim Verbinden mit der Wallbox deaktiviert. Siehe [docs.warp-charger.com](https://docs.warp-charger.com/docs/mqtt_http/api_reference/evse#evse_phase_auto_switch_warp3).
en: WARP's own automatic phase switching will be deactivated by EVCC when connecting to the wallbox. See [docs.warp-charger.com](https://docs.warp-charger.com/docs/mqtt_http/api_reference/evse#evse_phase_auto_switch_warp3).
evcc: ["skiptest"]
params:
- name: uri
@ -28,5 +26,5 @@ render: |
uri: {{ .uri }}
user: {{ .user }}
password: {{ .password }}
energyMeterIndex: {{ .energyMeterIndex }}
energyMeterIndex: {{ .energyMeterIndex }}
disablePhaseAutoSwitch: true

View file

@ -1,12 +1,11 @@
template: tinkerforge-warp-ws
template: tinkerforge-warp1-ws
products:
- { brand: TinkerForge, description: { generic: WARP2 Smart } }
- { brand: TinkerForge, description: { generic: WARP2 Pro } }
- { brand: TinkerForge, description: { generic: WARP1 Smart } }
- { brand: TinkerForge, description: { generic: WARP1 Pro } }
capabilities: ["mA", "1p3p", "rfid"]
capabilities: ["mA", "rfid"]
requirements:
description:
de: Die automatische Phasenumschaltung bei 1p Fahrzeugen muss deaktiviert sein. Siehe [docs.warp-charger.com](https://docs.warp-charger.com/docs/mqtt_http/api_reference/evse#evse_phase_auto_switch_warp3).
en: The automatic phase switching for 1p vehicles must be deactivated. See [docs.warp-charger.com](https://docs.warp-charger.com/docs/mqtt_http/api_reference/evse#evse_phase_auto_switch_warp3).
evcc: ["skiptest"]
params:
- name: uri

View file

@ -1,18 +1,26 @@
template: tinkerforge-warp2-ws
template: tinkerforge-warp2-em-ws
products:
- { brand: TinkerForge, description: { generic: WARP2 Smart + Energy Manager } }
- { brand: TinkerForge, description: { generic: WARP2 Pro + Energy Manager } }
capabilities: ["mA", "1p3p", "rfid"]
requirements:
description:
en: Firmware v2 required. Automatic phase switching requires the additional WARP Energy Manager.
de: Firmware v2 erforderlich. Für automatische Phasenumschaltung wird zusätzlich der WARP Energy Manager benötigt.
de: Firmware v2 erforderlich. Die WARP-eigene automatische Phasenumschaltung wird von EVCC beim Verbinden mit der Wallbox deaktiviert. Siehe [docs.warp-charger.com](https://docs.warp-charger.com/docs/mqtt_http/api_reference/evse#evse_phase_auto_switch_warp3).
en: Firmware v2 required. WARP's own automatic phase switching will be deactivated by EVCC when connecting to the wallbox. See [docs.warp-charger.com](https://docs.warp-charger.com/docs/mqtt_http/api_reference/evse#evse_phase_auto_switch_warp3).
evcc: ["skiptest"]
params:
- name: uri
required: true
- name: user
- name: password
- name: energyMeterIndex
advanced: true
default: 0
description:
generic: Energy Meter Index
help:
de: Index des in der Warp konfigurierten Meters dessen Werte genutzt werden sollen.
en: Index of the meter configured in the WARP charger whose values should be used.
- name: energyManagerUri
description:
generic: Energy Manager URI
@ -41,4 +49,5 @@ render: |
energyManagerUri: {{ .energyManagerUri }}
energyManagerUser: {{ .energyManagerUser }}
energyManagerPassword: {{ .energyManagerPassword }}
energyMeterIndex: {{ .energyMeterIndex }}
disablePhaseAutoSwitch: true