Em2go: improve connection robustness (#29351)

This commit is contained in:
A. Veseli 2026-04-27 17:48:42 +02:00 • committed by GitHub
parent 35b033324b
commit 67588c2d66
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 60 additions and 1 deletions

View file

@ -101,9 +101,32 @@ func NewEm2GoDuo(ctx context.Context, uri string, slaveID uint8, connector int)
connector: connector,
}
b, err := wb.conn.ReadHoldingRegisters(em2GoDuoRegCommTimeout, 1)
if err != nil {
return nil, fmt.Errorf("failsafe timeout: %w", err)
}
if u := binary.BigEndian.Uint16(b); u > 0 {
go wb.heartbeat(ctx, time.Duration(u)*time.Second/2)
}
return wb, nil
}
// heartbeat keeps the Modbus connection alive to prevent the charger from
// entering its failsafe state when the configured communication timeout expires.
func (wb *Em2GoDuo) heartbeat(ctx context.Context, interval time.Duration) {
for tick := time.Tick(interval); ; {
select {
case <-tick:
if _, err := wb.conn.ReadHoldingRegisters(em2GoDuoRegSafeCurrent, 1); err != nil {
wb.log.ERROR.Println("heartbeat:", err)
}
case <-ctx.Done():
return
}
}
}
// Status implements the api.Charger interface
func (wb *Em2GoDuo) Status() (api.ChargeStatus, error) {
b, err := wb.conn.ReadHoldingRegisters(em2GoDuoRegConnectorState, 1)

View file

@ -23,6 +23,7 @@ import (
"fmt"
"time"
"github.com/cenkalti/backoff/v4"
"github.com/evcc-io/evcc/api"
"github.com/evcc-io/evcc/util"
"github.com/evcc-io/evcc/util/modbus"
@ -108,7 +109,42 @@ func NewEm2Go(ctx context.Context, uri string, slaveID uint8) (api.Charger, erro
current: 60,
}
return wb.initialize()
bo := backoff.WithContext(
backoff.NewExponentialBackOff(
backoff.WithInitialInterval(2*time.Second),
backoff.WithMaxInterval(10*time.Second),
backoff.WithMaxElapsedTime(30*time.Second),
), ctx)
res, err := backoff.RetryWithData(wb.initialize, bo)
if err != nil {
return nil, err
}
b, err := wb.conn.ReadHoldingRegisters(em2GoRegCommTimeout, 1)
if err != nil {
return nil, fmt.Errorf("failsafe timeout: %w", err)
}
if u := binary.BigEndian.Uint16(b); u > 0 {
go wb.heartbeat(ctx, time.Duration(u)*time.Second/2)
}
return res, nil
}
// heartbeat keeps the Modbus connection alive to prevent the charger from
// entering its failsafe state when the configured communication timeout expires.
func (wb *Em2Go) heartbeat(ctx context.Context, interval time.Duration) {
for tick := time.Tick(interval); ; {
select {
case <-tick:
if _, err := wb.conn.ReadHoldingRegisters(em2GoRegSafeCurrent, 1); err != nil {
wb.log.ERROR.Println("heartbeat:", err)
}
case <-ctx.Done():
return
}
}
}
// initialize performs common initialization for both Em2Go models