diff --git a/charger/warp-ws.go b/charger/warp-ws.go index 16a4aab8e..32a0f3f5d 100644 --- a/charger/warp-ws.go +++ b/charger/warp-ws.go @@ -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 } diff --git a/templates/definition/charger/tinkerforge-warp-ws.yaml b/templates/definition/charger/tinkerforge-warp-ws.yaml index 480213cea..9feac2e9a 100644 --- a/templates/definition/charger/tinkerforge-warp-ws.yaml +++ b/templates/definition/charger/tinkerforge-warp-ws.yaml @@ -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 diff --git a/templates/definition/charger/tinkerforge-warp1-ws.yaml b/templates/definition/charger/tinkerforge-warp1-ws.yaml index 139025e0d..c15bd032a 100644 --- a/templates/definition/charger/tinkerforge-warp1-ws.yaml +++ b/templates/definition/charger/tinkerforge-warp1-ws.yaml @@ -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 diff --git a/templates/definition/charger/tinkerforge-warp2-ws.yaml b/templates/definition/charger/tinkerforge-warp2-em-ws.yaml similarity index 58% rename from templates/definition/charger/tinkerforge-warp2-ws.yaml rename to templates/definition/charger/tinkerforge-warp2-em-ws.yaml index e3c75a3e1..3e58232b7 100644 --- a/templates/definition/charger/tinkerforge-warp2-ws.yaml +++ b/templates/definition/charger/tinkerforge-warp2-em-ws.yaml @@ -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