From 798177c995d856d64e095b4fc91ce2b1ab2d5228 Mon Sep 17 00:00:00 2001 From: Markus Kaindl Date: Sat, 20 Jun 2026 02:28:07 +0200 Subject: [PATCH 1/3] openwb-2.0: implement RFID Reset --- charger/openwb-2.0.go | 26 +++++++++++++------- templates/definition/charger/openwb-2.0.yaml | 11 ++++----- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/charger/openwb-2.0.go b/charger/openwb-2.0.go index 19dcbb10794..eb238555413 100644 --- a/charger/openwb-2.0.go +++ b/charger/openwb-2.0.go @@ -14,10 +14,11 @@ import ( // OpenWB20 charger implementation type OpenWB20 struct { implement.Caps - conn *modbus.Connection - enabled bool - curr uint16 - base uint16 + conn *modbus.Connection + enabled bool + curr uint16 + base uint16 + laststatus api.ChargeStatus } const ( @@ -34,6 +35,7 @@ const ( openwbRegPhaseTarget = 10180 openwbRegPhaseTrigger = 10181 openwbRegHeartbeat = 10190 + openwbRegResetRfid = 10197 openwbRegCpTrigger = 10198 ) @@ -90,10 +92,11 @@ func NewOpenWB20(ctx context.Context, uri string, slaveID uint8, connector uint1 conn.Logger(log.TRACE) wb := &OpenWB20{ - Caps: implement.New(), - conn: conn, - curr: 6 * 100, - base: (connector - 1) * 100, + Caps: implement.New(), + conn: conn, + curr: 6 * 100, + base: (connector - 1) * 100, + laststatus: api.StatusNone, } return wb, nil @@ -102,13 +105,18 @@ func NewOpenWB20(ctx context.Context, uri string, slaveID uint8, connector uint1 // Status implements the api.Charger interface func (wb *OpenWB20) Status() (api.ChargeStatus, error) { if b, err := wb.conn.ReadInputRegisters(wb.base+openwbRegCharging, 1); err != nil || binary.BigEndian.Uint16(b) == 1 { + wb.laststatus = api.StatusC return api.StatusC, err } if b, err := wb.conn.ReadInputRegisters(wb.base+openwbRegPlugged, 1); err != nil || binary.BigEndian.Uint16(b) == 1 { + wb.laststatus = api.StatusB return api.StatusB, err } - + if wb.laststatus != api.StatusA { + wb.conn.WriteSingleRegister(wb.base+openwbRegResetRfid, 1) // Reset RFID on disconnect + } + wb.laststatus = api.StatusA return api.StatusA, nil } diff --git a/templates/definition/charger/openwb-2.0.yaml b/templates/definition/charger/openwb-2.0.yaml index 8f436bbea88..5bf2f2a158a 100644 --- a/templates/definition/charger/openwb-2.0.yaml +++ b/templates/definition/charger/openwb-2.0.yaml @@ -3,7 +3,7 @@ products: - brand: openWB description: generic: Software 2.x -capabilities: ["mA", "1p3p", "meter", "dim"] +capabilities: ["mA", "1p3p", "meter", "dim", "rfid"] requirements: description: de: | @@ -13,7 +13,7 @@ requirements: * Steuerungsmodus: `secondary` * Steuerung über Modbus als secondary: `An` - RFID-Autorisierung ist mit openWB Software 2.x leider aktuell nicht sinnvoll nutzbar, siehe + RFID-Autorisierung ist erst ab openWB Software 2.3.0 sinnvoll nutzbar, siehe [`openWB Issue 2832`](https://github.com/openWB/core/issues/2832) en: | Requires [`Software 2.x`](https://github.com/openWB/core). @@ -22,7 +22,7 @@ requirements: * Steuerungsmodus: `secondary` * Steuerung über Modbus als secondary: `An` - RFID-Authorisation currently is not usable with openWB Software 2.x, check + RFID-Authorisation currently is only usable with openWB Software version starting from 2.3.0, check [`openWB Issue 2832`](https://github.com/openWB/core/issues/2832) params: - name: modbus @@ -43,9 +43,8 @@ params: en: Use RFID-Reader de: RFID-Reader verwenden help: - en: Be sure to check [`openWB Issue 2832`](https://github.com/openWB/core/issues/2832) before enabling this, should not be used for access protection! - de: Unbedingt [`openWB Issue 2832`](https://github.com/openWB/core/issues/2832) beachten, sollte nicht für Zugangsschutz verwendet werden! - advanced: true + en: Be sure to update openWB to version 2.3.0 or greater before using this for access protection! + de: openWB muss mindestens auf Version 2.3.0 aktualisiert werden, bevor RFID für den Zugangsschutz verwendet wird! render: | type: openwb-2.0 {{- include "modbus" . }} From dfef4186db7881343f259ac32ce2235761a336a8 Mon Sep 17 00:00:00 2001 From: Markus Kaindl Date: Thu, 13 Aug 2026 03:25:42 +0200 Subject: [PATCH 2/3] Extend RFID reset handling for OpenWB20 charger implementation Reset RFID also, if new Tag is scanned while in status A and no car gets connected in the next 2 minutes --- charger/openwb-2.0.go | 52 ++++++++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/charger/openwb-2.0.go b/charger/openwb-2.0.go index eedb46cbb5e..2668d0c0a97 100644 --- a/charger/openwb-2.0.go +++ b/charger/openwb-2.0.go @@ -4,6 +4,7 @@ import ( "context" "encoding/binary" "fmt" + "time" "github.com/evcc-io/evcc/api" "github.com/evcc-io/evcc/api/implement" @@ -14,11 +15,13 @@ import ( // OpenWB20 charger implementation type OpenWB20 struct { implement.Caps - conn *modbus.Connection - enabled bool - curr uint16 - base uint16 - laststatus api.ChargeStatus + conn *modbus.Connection + enabled bool + curr uint16 + base uint16 + laststatus api.ChargeStatus + lastidentify string + lastidtime time.Time } const ( @@ -92,16 +95,41 @@ func NewOpenWB20(ctx context.Context, settings modbus.TcpSettings, connector uin conn.Logger(log.TRACE) wb := &OpenWB20{ - Caps: implement.New(), - conn: conn, - curr: 6 * 100, - base: (connector - 1) * 100, - laststatus: api.StatusNone, + Caps: implement.New(), + conn: conn, + curr: 6 * 100, + base: (connector - 1) * 100, + laststatus: api.StatusNone, + lastidentify: "", + lastidtime: time.Unix(0, 0), } return wb, nil } +func (wb *OpenWB20) HandleRfidReset() { + if wb.laststatus != api.StatusA { + wb.conn.WriteSingleRegister(wb.base+openwbRegResetRfid, 1) // Reset RFID on disconnect + return + } + new_id, _ := wb.identify() + if new_id == "" { + wb.lastidentify = "" + wb.lastidtime = time.Unix(0, 0) + return + } + if wb.lastidentify != new_id { + wb.lastidentify = new_id + wb.lastidtime = time.Now() + return + } + if wb.lastidtime != time.Unix(0, 0) && time.Since(wb.lastidtime) > 2*time.Minute { + wb.conn.WriteSingleRegister(wb.base+openwbRegResetRfid, 1) // Reset RFID after timeout + wb.lastidentify = "" + wb.lastidtime = time.Unix(0, 0) + } +} + // Status implements the api.Charger interface func (wb *OpenWB20) Status() (api.ChargeStatus, error) { if b, err := wb.conn.ReadInputRegisters(wb.base+openwbRegCharging, 1); err != nil || binary.BigEndian.Uint16(b) == 1 { @@ -113,9 +141,7 @@ func (wb *OpenWB20) Status() (api.ChargeStatus, error) { wb.laststatus = api.StatusB return api.StatusB, err } - if wb.laststatus != api.StatusA { - wb.conn.WriteSingleRegister(wb.base+openwbRegResetRfid, 1) // Reset RFID on disconnect - } + wb.HandleRfidReset() wb.laststatus = api.StatusA return api.StatusA, nil } From d8432c4ce0950c10d3cf282c1b67410c540623f4 Mon Sep 17 00:00:00 2001 From: Markus Kaindl Date: Thu, 13 Aug 2026 03:29:30 +0200 Subject: [PATCH 3/3] openwb-2.0: Use cached values on read error at the moment random status changes occur on read errors; as we need cached values of status and identifier for RFID-Reset, use these in case of read errors --- charger/openwb-2.0.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/charger/openwb-2.0.go b/charger/openwb-2.0.go index 2668d0c0a97..9d95ec9b080 100644 --- a/charger/openwb-2.0.go +++ b/charger/openwb-2.0.go @@ -132,12 +132,19 @@ func (wb *OpenWB20) HandleRfidReset() { // Status implements the api.Charger interface func (wb *OpenWB20) Status() (api.ChargeStatus, error) { - if b, err := wb.conn.ReadInputRegisters(wb.base+openwbRegCharging, 1); err != nil || binary.BigEndian.Uint16(b) == 1 { + b, err := wb.conn.ReadInputRegisters(wb.base+openwbRegCharging, 1) + if err != nil { + return wb.laststatus, err + } + if binary.BigEndian.Uint16(b) == 1 { wb.laststatus = api.StatusC return api.StatusC, err } - - if b, err := wb.conn.ReadInputRegisters(wb.base+openwbRegPlugged, 1); err != nil || binary.BigEndian.Uint16(b) == 1 { + b, err = wb.conn.ReadInputRegisters(wb.base+openwbRegPlugged, 1) + if err != nil { + return wb.laststatus, err + } + if binary.BigEndian.Uint16(b) == 1 { wb.laststatus = api.StatusB return api.StatusB, err } @@ -264,7 +271,7 @@ func (wb *OpenWB20) WakeUp() error { func (wb *OpenWB20) identify() (string, error) { b, err := wb.conn.ReadInputRegisters(wb.base+openwbRegRfid, 10) if err != nil { - return "", err + return wb.lastidentify, err } return bytesAsString(b), nil }